参考自StackOverflow
如果你细心的研究过对象内部有什么东西,你会发现,就算我创建一个非常简单的对象,打开它的内部,也会看到许多有趣的东西,而且但凡是对象都会有一个叫做__proto__
的属性,如果是类|构造函数|Function
和Object
,还会有一个叫做prototype
的 *属性|对象 *,比方说:
var a = new Object()
or
var a = {}
现在,在全局(global)对象中,创建了一个空的实例(在C++,python,java这一类面向对象语言中,我们喜欢把new创建出来的对象叫做实例对象),那么a就真的是空的实例对象 吗,其实不然。
展开a实例对象以后 通过VScode观察当我们展开这个实例对象 以后看到了a 实例对象 中存在一个
__proto__
属性|对象,那么它是怎么来的呢?如果弄懂了它,那么你对理解原型链继承的本质又接近了一步。
那么下面我来公布一下答案。JavaScript是一个基于原型链继承的语言,所以我们知道,在javascript世界中所有对象的 *造物主 *就是Object
(注意,这里的Object第一个字母是大写)所有的对象最终都会链接到Object
这个东西,所以a实例对象
的造物主就是Object
,很自然,的a 实例对象 的__proto__
其实就是Object的prototype
对象|属性。
a.__proto__ === Object.prototype // ==> true
这就意味着,实例对象的
__proto__
属性就是从创建它的类(也就是被new的那个类)的prototype 属性|对象!!!划重点
让我们来看一个更加复杂一点的例子
如果还想进一步了解真相请继续阅读
下面是一个在stackoverflow上的一个问题,了解这个问题会很有帮助。
Q(question):
这张图片展现每一个(es6中的class类对象与es5中的function对象)对象都有一个prototype
。构造器函数(Constructor function) Foo 同样也有它自己的__proto__
对象|属性|特性 ,而且这个属性 继承|引用|来自 Function.prototype
,又通过它(Function.prototype)的__proto__
属性再次 引用到
|继承自 Object.prototype
(看到没有,这就是一条原型链)。
提问者的所展示的实例代码:
var b = new Foo(20);
var c = new Foo(30);
完整的示例代码:
// 一个构造函数(construct function)
function Foo(y) {
// 这个函数创建实例对象通过
// 特定的模式: 被这个够着函数创建
// 创建的*实例对象*都有一个叫做 "y" 的属性
this.y = y;
}
// 同时 "Foo.prototype" 存储了指向新的被创建的的对象的*引用(reference)*的原型,
// 所以我们可能利用它来定义 *被共享|被继承* 的属性(properties)或者方法(methods),
// 所以同样的,在之前的例子中我们有:
// 被继承的属性 "x"
Foo.prototype.x = 10;
// 以及被继承的方法 "calculate"
Foo.prototype.calculate = function (z) {
return this.x + this.y + z;
};
// 现在,通过 "pattern" Foo
// 创建我们的*实例对象* "b" 和 "c"
var b = new Foo(20);
var c = new Foo(30);
// 调用被继承的方法
b.calculate(30); // 60
c.calculate(40); // 80
// 让我们观察一下我们期望的 *引用(reference)* 属性
console.log(
b.__proto__ === Foo.prototype, // true
c.__proto__ === Foo.prototype, // true
// 同样的 "Foo.prototype" 自动的创建了
// 一个特别的属性叫做 "constructor",这个属性是一个指向
// *构造函数*自身的 *引用*;
// 实例化 "b" 和 "c" *实例对象*的时候,可能会通过
//*委托(delegation)*找到它 和 用于检测他们的构造器(constructor)
b.constructor === Foo, //==> true
c.constructor === Foo, // ==> true
Foo.prototype.constructor === Foo, // ==>true
b.calculate === b.__proto__.calculate, // ==>true
b.__proto__.calculate === Foo.prototype.calculate // ==>true
);
这段代码之间的关系被展现为下面这幅图
这张图是从这里来的
因此我要 重点强调 * 一下,Foo.prototype只是Foo对象的一个显式的属性,而这个属性时被实例对象b和实例对象* c 引用|指向 的.
那么prototype
与__proto__
属性有什么区别呢?
A(answer):
__proto__
是用于查找原型链中方法等等(比方说一般的属性)的实际对象,当你用new来创建一个对象的时候,类(es6中叫class的语法糖)或函数(es5中的都用function来创建类)的prototype
是用来构建实例的__proto__
对象的对象。
:
( new Foo ).__proto__ === Foo.prototype
( new Foo ).prototype === undefined
网友评论