We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ECMAScript 中提供了构造函数来创建新对象。但构造函数本身就是一个函数,与普通函数没有任何区别,只不过为了区分,一般将其首字母大写,但这并不是必须的。
函数被 new 关键字调用时就是构造函数。
function f(name) { console.log("execute"); this.name = name; } var k = new f("k"); // execute console.log(k); // {name: "k"} var h = f("h"); // execute console.log(h); // undefined
从上面代码可以看出:
对象由构造函数通过 new 关键字创造,那么是如何创造的呢?
new 关键字的内部实现机制:
var obj = {}; // 创建一个空对象 obj.__proto__ = constructor.prototype; // 添加__proto__属性,并指向构造函数的 prototype 属性。 constructor.call(this); // 绑定this return obj;
每一个函数都有一个 prototype 属性。
prototype
function Foo() {} Foo.prototype; // {constructor,__proto__}
无论什么时候,只要创建了一个新函数,根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。
那么这个创建的原型对象是什么呢?
{ constructor: ƒ Foo(), __proto__: Object }
每一个原型对象都有一个 constructor 属性
constructor
创建了自定义的构造函数后,其原型对象只会默认取得 constructor 属性。这个属性解决了对象识别问题,即可以通过该属性判断出实例是由哪个构造函数创建的。
Foo.prototype.constructor === Foo; // true
前面说了,原型对象只会默认取得 constructor 属性,那么原型对象的其他属性(比如:__proto__ )是这么来的呢,这就要说到 __proto__ 指针了。
__proto__
每一个实例都有一个 __proto__ 指针,指向构造函数的原型对象。
var foo = new Foo(); foo.__proto__ === Foo.prototype; //true
上面提到的构造函数的原型对象它本身也是一个实例,所以在它内部会有一个 __proto__ 指针。
想要知道构造函数的原型对象是由什么创建的吗?
活学活用,这里我们可以使用刚刚学到对象指向问题判断的知识。我们想要知道 constructor,那么可以通过实例的原型对象(因为每一个原型对象都有一个 constructor 属性),所以我们可以这样操作:
Foo.prototype.__proto__.constructor // ƒ Object() { [native code] }
这说明,构造函数的原型的原型是由 Object 生成的!!所以,构造函数原型对象的其他方法,则是从 Object 上继承来的。
Foo.prototype.__proto__ === Object.prototype; // true
原型链的理论主要基于上述提到的构造函数、实例和原型的关系:
其中最最重要的是第三条,依赖这条关系,层层递进,就形成了实例与原型的链条。
我接着上面的探索,构造函数的原型的原型是由 Object 生成的,那么 Object 的原型是由什么生成?而原型链的终点又是在哪?
Object.prototype.__proto__ // null null.__proto__; // Uncaught TypeError: Cannot read property '__proto__' of null // game over
原型的终点是 null,因为 null 没有 proto 属性。
哇,感觉这很符合创世纪的故事啊—— “初始,一切且不存在(null)”。
tips: 其实 null 是基本数据类型,typeof null 返回 object 是 ECMAScript 设计上的一个错误
最后,一图胜千言:
The text was updated successfully, but these errors were encountered:
No branches or pull requests
构造函数
ECMAScript 中提供了构造函数来创建新对象。但构造函数本身就是一个函数,与普通函数没有任何区别,只不过为了区分,一般将其首字母大写,但这并不是必须的。
函数被 new 关键字调用时就是构造函数。
从上面代码可以看出:
对象由构造函数通过 new 关键字创造,那么是如何创造的呢?
new 关键字的内部实现机制:
prototype
无论什么时候,只要创建了一个新函数,根据一组特定的规则为该函数创建一个 prototype 属性,这个属性指向函数的原型对象。
那么这个创建的原型对象是什么呢?
constructor 属性
创建了自定义的构造函数后,其原型对象只会默认取得
constructor
属性。这个属性解决了对象识别问题,即可以通过该属性判断出实例是由哪个构造函数创建的。前面说了,原型对象只会默认取得
constructor
属性,那么原型对象的其他属性(比如:__proto__
)是这么来的呢,这就要说到__proto__
指针了。__proto__
上面提到的构造函数的原型对象它本身也是一个实例,所以在它内部会有一个
__proto__
指针。想要知道构造函数的原型对象是由什么创建的吗?
活学活用,这里我们可以使用刚刚学到对象指向问题判断的知识。我们想要知道 constructor,那么可以通过实例的原型对象(因为每一个原型对象都有一个
constructor
属性),所以我们可以这样操作:这说明,构造函数的原型的原型是由 Object 生成的!!所以,构造函数原型对象的其他方法,则是从 Object 上继承来的。
原型链
原型链的理论主要基于上述提到的构造函数、实例和原型的关系:
__proto__
指针其中最最重要的是第三条,依赖这条关系,层层递进,就形成了实例与原型的链条。
我接着上面的探索,构造函数的原型的原型是由 Object 生成的,那么 Object 的原型是由什么生成?而原型链的终点又是在哪?
原型的终点是 null,因为 null 没有 proto 属性。
哇,感觉这很符合创世纪的故事啊—— “初始,一切且不存在(null)”。
tips: 其实 null 是基本数据类型,typeof null 返回 object 是 ECMAScript 设计上的一个错误
最后,一图胜千言:
The text was updated successfully, but these errors were encountered: