Just ran some tests on this in Unity 2017.1, with the new 4.6 .NET compiler, if anyone is interested.
Doing 100,000 calls to GetComponent and GetComponent and GetComponent:
Transform = 4ms (.00004ms / call)
Rigidbody = 4ms
Foo = 14ms (.00014ms / call)
So it appears as those native components are cached somehow, or at least about 3x faster to lookup than custom scripts, and while the custom GetComponent is still fairly fast, I think the performance hit still justifies caching, especially in your update loop.
Using a design pattern like this, you can get your custom scripts down to the same performance as native, without much extra code:
public T GetCachedComponent<T>(ref T c) where T : Component {
if (!c) { c = GetComponent<T>(); }
return c;
}
Foo foo;
public Foo Foo { get { return GetCachedComponent(ref foo); } }
Bar bar;
public Bar Bar { get { return GetCachedComponent(ref bar); } }
//etc
It has one big flaw though, if your component does not exist, performance spikes by 10x.
Doing 100,000 calls to GetComponent(), takes 450+ms(!), so you still need to be very careful you’re not calling this each frame to check if the component exists, it could burn you.
Overall, due to the very high costs of checking for a missing component, and the extra cost for custom components, I think best practice remains to manually inject your component dependancies in the editor, or wire them up once in your Start() method.