prototype还是__proto__,傻傻分不清
prototype和__proto__都是JavaScript(以下简称Js)里面用来实现继承的对象。Js里面叫做原型。__proto__是针对实例而言,而prototype则是针对类而言。
每个实例对象(object )都有一个私有属性(称之为__proto__)指向它的原型对象(prototype)。该原型对象也有一个自己的原型对象(proto) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
class A {
private a:number;
public aFunc(){}
}
class B extends A{
public static _ins:B;
private b:number=1;
public bFunc(){}
}
let b = new B();
(ES6中引入了class关键字,但是Js仍然是基于原型继承的。)
当我们执行
let b = new B()
,
实际上执行的是
let b = new Object();
b.__proto__ =B.prototype;
B.call(b);
我们通过new创建了一个b对象,b.__proto__实际指向的就是B.prototype。所以b对象的原型链就是b->B.prototype(相当于b.proto)->A.prototype->Object.prototype->null。当我们要查找b对象的某个属性或函数时,是先在b自有对象里查找,找不后到B.prototype里面查找,一层层向上,直至找到或到达原型链末端。(static将属性声明为静态类型,不能被继承,只能通过类名.属性名方式引用)。当我们使用new创建b1、b2…对象,它们和b对象一样,共享相同原型链中的属性和方法。也因此我们可以更改链中某个prototype,这种更改将会影响所有继承自它的所有实例。
遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject的原型。从 ECMAScript 6 开始,[[Prototype]] 可以通过Object.getPrototypeOf()和Object.setPrototypeOf()访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 proto。
遍历对象的属性时,原型链上的每个可枚举属性都会被枚举出来。要检查对象是否具有自己定义的属性,而不是其原型链上的某个属性,则必须使用所有对象从Object.prototype继承的 hasOwnProperty 方法。
注:扩展内置原型的唯一理由是支持JavaScript 引擎的新特性,如Array.forEach
在JS中,所有的东西都是对象。类实际上也是函数对象。b.__proto__中有个constructor函数,它实际指向的是构造b这个对象的构造函数,如下所示,就是function B()。
原型继承跟类式继承有些不同。类式继承通过构造函数继承,每一次实例,继承的属性和函数都会保存在内存中。而原型继承只会有将共享的属性和函数保存一份在原型对象中。此外,类式继承在运行时,不可以更改或扩展继承链上的函数。
最后,上一个其它地方看到的图:
写得不准确的地方,还望指正!