prototype也叫作显式原型,js里面每个函数都会有一个prototype属性,它是一个引用类型,指向的是一个函数的原型对象。
通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性。
__proto__叫隐式原型,js里面每个对象都会有一个__proto__属性,它指向的是创建这个对象的构造函数的prototype。
function A() {
this.a = "a";
this.a_func() = function() {
return this.a;
}
}
console.log(A.prototype);
console.log(A.__proto__);
A.prototype.b = "b";
var a = new A();
console.log(a.b); // b
a.__proto__.c = "c";
console.log(a.c); // c
console.log(a.__proto__ === A.prototype); // true
console.log(A.prototype.constructor === A); // true
执行结果:
解释:
- A()是一个函数,它拥有prototype属性,它指向一个函数的原型对象,在你没有手动指定A.prototype = new xxx()的时候,它默认指向的是A的原型对象,从结果中看到,它是一个Object,里面有着function A()的实例可以共享的属性和方法
- js里面万物皆对象,Function是对象,Function.prototype也是对象,function A()同样是对象,它的__proto__指向的是A的构造函数,很明显它的构造函数是Function(),所以A.__proto__ === Function.prototype。
- 当实例化了一个A的对象a后,a的__proto__指向的就是它的构造函数A的prototype,故 a.__proto__ === A.prototype。
- 可以在A的原型对象prototype上添加属性和方法,这样所有的A的实例化对象都可以访问到这个属性和方法了
- 因为a.__proto__ === A.prototype,所以在实例a的__proto__上添加属性和方法是一样的。
- 从结果中看到,A.prototype也是一个对象,那么它自然就有一个__proto__属性,这个__proto__指向的是A.prototype的构造函数Object的prototype(原型对象的构造函数都为Object),最后规定Object.prototype.__proto__ === null
所以,总的来说,我理解的函数的prototype就是指向一个对象,这个对象含有这个函数(可以理解成类)的实例可以共享的属性和方法;而__proto__就像一条链条,连接着所有的prototype与对象之间的关系,每当调用对象的方法的时候,就会先查找当前对象有没有这个方法,如果没有,就沿着这条__proto__链一直往上找,直到找到Object.prototype.__proto__ == null为止。
一个沿着原型链查找属性方法同时也是js类的继承的例子:
function A() {
this.a = "showWhere: " + "啊,你在A函数中找到了我!";
this.showWhere = function() {
return this.a;
}
}
A.prototype.xx = "沿着原型链自动查找到xx属性!"
A.prototype.showWhere = function() {
return "showWhere: " + "啊,你在A.prototype中找到了我!"
}
function B() {
this.showWhere = function() {
return "showWhere: " + "啊,你在B函数中找到了我!";
}
}
B.prototype = new A();
var b = new B();
console.log(b.a);
console.log(b.showWhere()); // 调用b对象的showWhere方法
console.log(b.__proto__.showWhere()); // 调用父类A的showWhere方法
console.log(b.__proto__.__proto__.showWhere());// 调用A.prototype的showWhere方法
console.log(b.xx);
执行结果:
一张图解释:
另补充一点,方法和属性除了显示地定义在this对象上(this.xxx=),默认为定义在原型对象prototype上。