该怎么透彻的理解prototype和_proto_,有没有通俗易懂的文章或书籍推荐?看过很多资料都比较绕
每个函数都有prototype
属性:
function Person(){}
Person.prototype.showName = function(){};
每个对象/实例都有__proto__
属性(ie除外),指向其构造函数的prototype
var a = new Person();
console.log(a.__proto__ === Person.prototype); //true
楼主看完这些答案肯定又迷糊了,楼主应该想为什么使用他,想明白为什么使用prototype
,简单来说就两个字:
实现继承
明白了js中的继承,再来看楼上的各位回答。
function A(){}
var a = new A()
a.__proto__ === A.prototype //true
感谢各位耐心解答,各位大神都有自己的理解,只有融会贯通了才能讲的出来,棒棒的!
prototype/__proto__/构造函数
prototype在我们将一个函数作为构造函数并通过其创建对象实例的时候才又威力作用,指向一个原型对象,记住指向的是一个对象哦;
也就是任何对象都可以作为prototype属性的值。在不对prototype属性重新赋值的情况下,prototype默认指向一个Object实例,并其constructor属性指向当前构造函数
例如
function A(){
}
A.prototype指向一个Object对象实例,这个Object对象是没有prototype属性的,其构造函数有prototype属性,指向Object实例
console.log(A.prototype.constructor===A);//true
console.log(A.prototype===A.prototype.constructor.prototype)//true
prototype属性用于指示使用构造函数创建的对象的基础对象是哪个
var a=new A();
console.log(a.prototype);//undefined 实例对象是没有prototype属性的
实例对象可以访问constructor属性,但并不是说实例对象拥有constructor属性,其访问的时其原型链上原型对象的constructor属性,
constructor属性告诉实例对象其是由哪个构造函数创建的
console.log(a.constructor===A);//true
console.long(a.hasOwnProperty("constructor"));//false
原型链式怎么回事呢,原型链通过实例对象的内部属性[[prototype]]构建起来的一条访问链条。
instanceof操作就是使用这个链条来判断一个实例对象是否是一个构造函数的实例
这个[[prototype]]属性在JS引擎实现上普遍使用__proto__名字来表示。其直接指向一个实例对象的原型对象-通过构造函数访问
console.log(a.__proto__===A.prototype);//true
function isInstanceOf(object,constructorFun){
var tmp=object;
var result=false;
while(tmp.__proto__){
if(tmp.__proto__===constructorFun.prototype){
result=true;
break;
}else{
tmp=tmp.__proto__;
}
}
return result;
}
function A(){}
function B(){}
function C(){}
B.prototype=new C();
A.prototype=new B();
var a=new A();
console.log(a.__proto__===A.prototype);//true
console.log(a.__proto__===B.prototype);//false
console.log(a.__proto__===C.prototype);//false
console.log(isInstanceOf(a,A));//true
console.log(isInstanceOf(a,B));//true
console.log(isInstanceOf(a,C));//true
console.log(a instanceof A);//true
console.log(a instanceof B);//true
console.log(a instanceof C);//true
通过以上我们可以总结出如下内容
prototype是构造函数的属性,指向一个对象。这个对象中有constructor属性指向构造函数
__proto__是一个实例对象的属性,其对象[[prototype]]内部属性的外在表现,利用__proto__我们可以访问实例对象的原型对象
并且instanceof操作符将使用__proto__属性来判断构造函数原型对象是否在一个对象原型链中的某处存在
但是,上面的代码如果执行:
console.log(a.constructor===A);//false
返回的结果却是false,是不是有点超出预期呢~~~
我们从直观上查看,实例对象a是通过A构造函数创建出来的,对象的构造函数应该是A;但是事实却非如此-是通过C构造函数创建的。
导致这个问题的原因就是我们重设prototype属性的指向,让其指向一个全新的对象~~,可以通过手工设置constructor属性的方式来修正
function A(){}
function B(){}
function C(){}
B.prototype=new C();
B.prototype.constructor=B;
A.prototype=new B();
A.prototype.constructor=A;
var a=new A();
console.log(a.constructor===A);//true
「你不知道的 JavaScript」
多看几遍
prototype是构造函数的一个属性,非构造函数是没有这个属性的。所以当你看到prototype这个东西时,一定要记着它是构造函数的一个属性。
例如:
String.prototype; // 存在
parseInt.property; // 不存在
__proto__是某些浏览器才支持的,它是对象的属性,一切对象都有此属性。当然也包括函数、构造函数。
我试着举一个形象的例子:
将函数
A
想象成一台制造馅饼的机器。馅饼呢,是在大饼的基础上加了馅后制作而成的。可以认为馅饼继承自大饼,或者说馅饼的原型是大饼。
-
现在开始制作了:首先要有一个大饼,也就是馅饼的原型。
var 大饼 = { // 省略具体定义 };
-
接着造一台馅饼机,即
function A() { this.有馅 = true; }
-
然后呢,告诉这台机器,要基于
大饼
来制造馅饼
。即A.prototype = 大饼;
-
然后呢,开始发动机器
A
,怎么发动呢?用new
。即var 馅饼 = new A();
OK,馅饼
造好了!
所以呢,prototype就是告诉函数这台机器,要基于一个什么样的模板来生成产品。__proto__就是生产出来的产品与制造它的那个模板产品之间的内部关联。
而且,我上面写的这些代码完全可以运行的,不信你可以试一试。结果是这样的: