原文是携程网UED的一篇中文翻译:http://ued.ctrip.com/blog/?p=2795&cpage=1#comment-38542,注意翻译的一些问题(见原文评论),本人只是参考了一下。
在了解概念之前,我们需要明白这几个概念是不是一回事儿:
JavaScript中有两个特殊的对象:Object与Function。Object.prototype是所有对象的原型,处于原型链的最底层。Function.prototype是所有函数对象的原型,包括构造函数。
我们看一个demo及图示:
代码:
// a constructor function function Foo(y) { this.y = y; }// inherited property "x" Foo.prototype.x = 10; // and inherited method "calculate" Foo.prototype.calculate = function (z) { return this.x + this.y + z; }; // now create our "b" and "c" // objects using "pattern" Foo var b = new Foo(20); var c = new Foo(30); // call the inherited method b.calculate(30); // 60 c.calculate(40); // 80 // let's show that we reference // properties we expect console.log( b.__proto__ === Foo.prototype, // true c.__proto__ === Foo.prototype, // true 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 );
图示:
一个对象的真正原型是被对象内部的[[Prototype]]属性(property)所持有。ECMA引入了标准对象原型访问器Object.getPrototype(object),到目前为止只有Firefox和chrome实现了此访问器。除了IE,其他的浏览器支持非标准的访问器__proto__,如果这两者都不起作用的,我们需要从对象的构造函数中找到的它原型属性。
上面一句话引自:http://blog.jobbole.com/9648/。
无论是哪篇文章也好,一个对象的原型我们其实还是有办法去访问的,IE除外。
好,根据代码和图,我们来给出一实例对象的一些结论,你可以假定存在__proto__这么一个东西:
再给出构造函数(函数)的有关原型的一些结论:
code:
/* *自定义的构造函数 */ var F=function(){}; var f1=new F(); console.log(f1.__proto===F.prototype);//true console.log(Function.prototype);//empty function console.log(F.__proto__===Function.prototype);//true console.log(Object.__proto__===Function.__proto__);//true console.log(f.constructor===F);//true /* *内置包装类,原理其实还是构造函数 */ var str='lalalala',str2=new String('llalalalla'); console.log(str.__proto__);//string类型 console.log(typeof str.__proto__);//运算转换成了object类型 console.log(str.__proto__===String.prototype);//true console.log(str2.__proto__===String.prototype);//true
console.log(Function instanceof Object);//true console.log(Object instanceof Function);//true console.log(Object.__proto__===Function.prototype);//true console.log(Function.__proto__===Object.prototype);//false,这个我就无法理解了,既然Function也是Object的实例,那么为何这个就错了呢 console.log(Function.__proto__===Object.__proto__);//true console.log(typeof Function);//function console.log(typeof Object);//function
给出两个代码示例:
demo1:
var F=function() { // body... } F.prototype={ show:function(){ }, hide:function(){ } }; console.log(F.constructor===Function);//true console.log(F.prototype.constructor===Object);//true
demo2:
var Parent=function(){}; var Son=function(){}; Son.prototype=new Parent(); var parent1=new Parent(); var son1=new Son(); console.log(parent1.constructor===Parent);//true console.log(son1.constructor===Parent);//true
从以上代码可以看出,一旦构造函数的prototype属性发生了更改,那么该构造函数的原型对象的constructor也就发生了改变(这不是废话么)。
通常情况下,构造函数实例化的对象的constructor属性指向其构造函数(最好说成指向其原型对象的constructor)。比如:
var A=function(){}; var a=new A(); console.log(a.constructor===A);//true
但是,构造函数的prototype属性发生了更改(构造函数的原型对象也就发生了改变),于是,构造函数实例化的对象的constructor属性也就变了。
鉴于以上出现的问题,通常有两种做法:
两种方法,各有利弊。如果要正确访问原型链,则使用第二种方法,虽然效率差了点;否则,请使用第一种方法。
---------------------------------------------------------------
其实,写这篇文章初期是为了证明:javascript中的原型是一个对象。但是后来发现函数(js中没有构造函数之说法)的__proto__属性指向的是Function.prototype,而这个只是个空函数。并非对象类型。
后来提了问题去segmentfault(详见:http://segmentfault.com/q/1010000000209832),看了作者的翻译,我才明白,javascript中往大了说,就是两种值类型:原始值和对象。所以函数也是对象,这一点也可以从new Function()这种创建函数的形式可以看出。