原型链中的 protorype __proto__
Foo = function(){}; Object.prototype.a = function(){console.log(1)}; Function.prototype.b = function(){console.log(2)}; var f = new Foo(); f.a() // 1 f.b() // throw error
上面的结果很令人费解,但如果了解javascript整个原型链的关系设计后答案就一目了然了。
在看上面的图之前我们要理解几个知识点:
1. new运算符 (创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例)
调用new运算符内部会做下面的事:
1. 创建空对象;
var obj = {};
2. 使 obj的内部属性 [[prototype]] 指向构造函数的原型对象prototype, chrome、firefox中可以通过 __proto__ 获取到,老版ie没有 __proto__ 这个属性;
obj.__proto__ = ClassA.prototype;
3. 使构造函数中的this被指向新实例对象obj,调用构造函数:
ClassA.call(obj); //{}.构造函数();
4. 构造函数的返回值如果不是引用类型的值,返回 obj,否则返回正常的返回值
2. 原型对象
只要创建一个新函数,会根据特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。上面的Foo函数就是新创建的函数,Foo函数有一个prototype属性指向原型对象。而这里的原型对象是通过Object构造函数 通过new创建的Object实例 (其实就是 {} )。Foo函数其实也是通过构造函数Function通过new创建的实例,所以Foo函数会有一个内置属性__proto__ 指向构造函数Function的原型对象prototype。
3.原型链(实现继承的主要方法)
每一个构造函数都会有个原型对象prototype,原型对象会有个curstructor指向这个构造函数,通过new创建的实例都会有个内部属性([[prototype]] 通过__proto__获取)指向构造函数的原型对象prototype。
__proto__ -> prototype
如果原型对象是另外一个类型的实例,那么这个原型对象中也会有个([[prototype]] 通过__proto__获取)指向构造函数的原型对象prototype,这样层层递进就构成了实例与原型的链条,也就是原型链。
__proto__ -> prototype (__proto__) -> prototype
上面题目中的 f函数 就好比是 图中的 new Foo() ,调用f.a()会先查找自己的属性中是否有a方法,如果没有的会通过原型链查找原型链上是否有a方法。f自身没有a方法,通过内部属性([[prototype]] 通过__proto__获取)找到了Foo构造函数的原型对象prototype,这个原型对象是构造函数Object的实列,所以Foo的原型对象中没有a方,再通过__proto__找到了Object的原型对象,最终找到了a方法。
console.log(Function.__proto__ === Function.prototype) //true console.log(Object.__proto__ === Function.prototype) //true console.log(String.__proto__ === Function.prototype) //true console.log(Array.__proto__ === Function.prototype) //true
console.log(Function.prototype.__proto__ === Object.prototype) //true console.log(String.prototype.__proto__ === Object.prototype) //true console.log(Array.prototype.__proto__ === Object.prototype) //true
内置函数的prototype和__proto__
Function,Object,Attay,String,Boolean 是系统的内置函数。每个内置函数都会有一个内置的原型对象prototype, 每个原型对象都会有内置属性([[prototype]] 通过__proto__获取)。我们平时调用的方法像: 数组的 push,pop,unshift,shift 字符串的 substring,split 都是原型对象中的方法。这里有2个比较特别的内置原型对象 Function.prototype 和 Object.prototype。
Object.prototype
所有构造函数的内置属性[[prototype]] 都指向Object.prototype, 除了Objec其他t所有内置函数的原型对象prototype的内置属性[[prototype]] 也都指Object.prototype,Object构造函数的内置属性[[prototype]]为 null。
(虽然是内置对象但是在原型链上就和通过new Foo构造的实例自带的原型对象是通过new Object获取的实例一样 内置属性[[prototype]]都指向Object.prototype原型对象)
Function.prototype
Function.prototype原型对象其实是个函数对象,可以像调用函数那样调用,返回值都为undefined。所有的内置函数的内置属性[[prototype]]都指向 Function.prototype原型对象。
(内置函数的内置属性[[prototype]]也和通过new Function构造的实例一样 内置属性[[prototype]]都指向 Function.prototype原型对象)