原型与原型链知识历来都是面试中考察的重点,说难不算太难,但要完全理解还是得下一定的功夫。先来看一道面试题开开胃口吧:
function User() {} User.prototype.sayHello = function() {} var u1 = new User(); var u2 = new User(); console.log(u1.sayHello === u2.sayHello); console.log(User.prototype.constructor); 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);
JavaScript所有的对象本质上都是通过new 函数创建的,包括对象字面量的形式定义对象(相当于new Object()的语法糖)。
所有的函数本质上都是通过new Function创建的,包括Object、Array等
所有的函数都是对象。
每个函数都有一个属性prototype,它就是原型,默认情况下它是一个普通Object对象,这个对象是调用该构造函数所创建的实例的原型。
JavaScript同样存在由原型指向构造函数的属性:constructor,即Func.prototype.constructor --> Func
JavaScript中所有对象(除了null)都具有一个__proto__属性,该属性指向该对象的原型。
function User() {} var u1 = new User(); // u1.__proto__ -> User.prototype console.log(u1.__proto__ === User.prototype) // true
显而易见,实例的__proto__属性指向了构造函数的原型,那么多个实例的__proto__会指向同一个原型吗?
var u2 = new User(); console.log(u1.__proto__ === u2.__proto__) // true
如果多个实例的__proto__都指向构造函数的原型,那么实例如果能通过一种方式,访问原型上的方法,属性等,就可以在原型进行编程,实现继承的效果。
我们继续更新一下原型与原型链的关系图:
实例对象在查找属性时,如果查找不到,就会沿着__proto__去与对象关联的原型上查找,如果还查找不到,就去找原型的原型,直至查到最顶层,这也就是原型链的概念。
就借助面试题,举几个原型链的例子:
举例
学完上面那些,大多数面试题都可以做出来了,例如下面这种
function A() {} function B(a) { this.a = a; } function C(a) { if (a) { this.a = a; } } A.prototype.a = 1; B.prototype.a = 1; C.prototype.a = 1; console.log(new A().a); //1 console.log(new B().a); //undefined console.log(new C(2).a); //2
但距离解决文章的最初的面试题还欠缺些什么,比如Function.__proto__ === Object.__proto__、Function.prototype.__proto__ === Object.prototype.__proto__等,接着我们来一一攻克它。
Objcet.__proto__ 、 Object.prototype、Object.prototype.__proto__
// 总结: Object.__proto__ --> Function.prototype Object.prototype.__proto__ --> null
Function.__proto__、Function.prototype、Function.prototype.__proto__
实践证明只存在Object.__proto__ --> Function.prototype
苦思冥想没得出结果,难道Function函数是猴子不成,从石头缝里面蹦出来的?于是我进行了一同乱七八糟的测试,没想到找出了端倪。
通过上面我们可以得出:Function.__proto__ --> Function.prototype
Function函数不通过任何东西创建,JS引擎启动时,添加到内存中
最后将原型与原型链方面的知识凝结成一张图:
知识的海洋往往比想象中还要辽阔,原型与原型链这边也反复的学过多次,我认为应该学的比较全面,比较完善了。但遇到这个面试题后,我才发现我所学的只不过是一根枝干,JS里面真的有很多深层次的宝藏等待挖掘。学海无涯,与君共勉。
最后再附赠个简单的面试题,提高一下自信:
var F = function () {} Object.prototype.a = function () {} Function.prototype.b = function () {} var f = new F(); console.log(f.a, f.b, F.a, F.b); // 原型链 // f.__proto__ --> F.prototype --> Object.prototype // F.__proto__ --> Function.prototype --> Object.prototype