何谓“链”

链表?链条?在 JavaScript 中都不是
JavaScript 中的每一个对象都有一个特殊的内置属性[[Prototype]]可以通过__proto__进行访问。他指向的是一个原型对象。当我们访问一个对象的某个属性的时候,如果对象本身没有这个属性,就会向其原型查找,如果找到了就停止,如果没找到则为undefined(未定义),比如当我们 new 一个对象,我们根本就没有定义 toString 方法呀,但是它就在那里,不在这个对象身上,在它的原型链上!

Function? Object? 你是谁?

先看一段代码

1
console.log(Function.__proto__ === Object.__proto__)

猜猜会输出什么,true
在 JavaScript 里面,万物皆对象,所以函数也是对象,它叫做函数对象,所以一个函数身上会有__proto__这个属性就不奇怪了。

然而,在学习的过程中,函数不仅仅有__proto__这个属性,还有另外一个属性prototype,这两个又有什么区别呢?

不妨假设现在有一个函数 fn ,它的定义如下

1
2
3
function fn(){
console.log("js是世界上最好的编程语言!")
}
  1. fn.__proto__指向什么 ?
    fn 是一个函数对象,他的__proto__指向他的原型,也就是Function.prototype,因为在 JavaScript 中所有的函数都是通过 Function 构造函数创建的, 所以他们的__proto__指向的是Function.prototype

  2. fn.prototype指向什么?
    fn.prototype是一个对象,包含了所有 fn 实例所将要继承的属性和方法。当我们使用 new fn()创建一个新的实例的时候,这个新的实例的__proto__都会指向fn.prototype,纳尼! fn 不是一个方法吗,怎么会有属性!方法也是对象,小子。
    es6 的 extends 关键字就是基于这个实现的

所以也就不难理解为什么typeof fn.__proto__function,而typeof fn.prototypeobject

再来看一个有趣的东西

1
console.log(Function.__proto__ === Function.prototype)

猜猜会输出什么,true

晕了哈哈哈哈,这是比较特殊的部分,他们都指向 Function 原型,记住就好了

原型链一图流

狠狠的推导,这张图无敌!

1
2
3
4
5
6
7
8
9
10
11
12
13
function User(){};
User.prototype.sayHi = function(){};
var u1 = new User();
var u2 = new User();
console.log(u1.sayHi === u2.sayHi);
console.log(User.prototype === Function.prototype);
console.log(User.__proto__ === Function.prototype);
console.log(User.__proto__ === Function.__proto__);
console.log(u1.__proto__ === u2.__proto__);
console.log(u1.__proto__ === User.__proto__);
console.log(Function.__proto__ === Object.__proto__);
console.log(Function.prototype.__proto__ === Object.prototype.__proto__);
console.log(Function.prototype.__proto__ === Object.prototype);

true
false
true
true
true
false
true
false
true