一直恪守的原则就是,要用一个东西,那么一定要对这个东西非常的了解才可以,这样在用的时候才能做到心里有底、、或者说心里有数。。。。接触node.js也算是有一段的时间了,也拿它做了一些的东西,以前的一片文章算是分析了javascript的闭包原理,但是自己一直没有将javascript的原型机制搞清楚,趁着现在比较的闲,静下来将这一块先搞定。。。。
首先我们来看一句比较奇怪的代码:
console.log(typeof Object);
这里的输出会比较的神奇:function
也就是说Object本身是一个function,那么我们用如下的代码来看看这个Object这个function是怎么定义的吧:
console.log(Object.toString());
那么这段代码的输出是: function Object() { [native code] }
好吧,到这里我们可以下结论Object是一个函数,而且这个函数的实现是javascript引擎内部的,对于这部分就无能为力了。。。
根据《javascript高级程序设计》以及《javascript语言精粹》的说法,可以画出如下的图形:
这里因为Object是一个function,所以它有一个prototype属性和一个name属性,name的属性的值就是“Object”,而prototype则指向了它的原型对象,而其原型对象中又包含一个constructor属性指向当前的Object函数。。。
好了,接下来我们来看看按照对象字面量创建对象吧,代码:
var aa = {};
aa.name = 'fjs';
上面通过字面量的方式创建了一个对象,并用aa来引用它,而且给了它一个name的属性,这个时候可以用如下的图来表示aa:
上图的意思就是说刚刚创建的aa对象中有一个名字叫做__proto__的属性指向了Object的prototype,而且这个属性是默认添加上去的,这是一个内部的属性,默认按照ECMA的规定,它是不可以访问的,但是很多javascript引擎都通过__proto__这个名字来引用这个属性。。
我们可以用如下的代码来验证:
var aa = {};
aa.name = 'fjs';
console.log(aa.__proto__ === Object.prototype);
输出的结果是true,那么上面的图形也就得到了验证。。。
接下来我们来看看另外一种构造对象的方法,构造函数,先来看一个构造函数的定义:
function Fjs() {
this.name = "fjs";
}
这里我们用另外一张图来表示当前的情形:
这张图形可以用如下的代码进行验证:
function Fjs() {
this.name = "fjs";
}
console.log(Fjs.prototype.constructor === Fjs);
console.log(Fjs.prototype.__proto__ === Object.prototype);
上述的两个输出都是true,那么上面的图形也就得到了验证,接下来我们来看看调用构造函数来创建对象都做了什么事情,也就是如下代码:
function Fjs() {
this.name = "fjs";
}
console.log(Fjs.prototype.constructor === Fjs);
console.log(Fjs.prototype.__proto__ === Object.prototype);
var fjs = new Fjs();
这种方式构造对象,其实javascript引擎是这么搞的:
(1)创建一个新的对象
(2)将当前构造函数的作用域指向刚刚创建的新对象,也就是将构造函数的this指向刚刚创建的对象,而且要为这个对象的内部__proto__属性赋值,用它指向当前构造函数的prototype属性
(3)执行构造函数中的代码,也就是调用this,为刚刚创建的对象赋值
(4)返回该对象
那么根据上述的步骤,我们又可以得到如下的图形:
对于上述的图形,我们可以用如下的代码来进行验证:
function Fjs() {
this.name = "fjs";
}
var fjs = new Fjs();
console.log(fjs.__proto__ == Fjs.prototype);
输出是true,那么上述的图形也就得到了验证,其实从这里也就能够看到javascript所谓的原型链了。。。
到这里为止应该算是对javascript的原型模式有了一定的了解了吧。。不至于像以前一样裸奔了。。。