本来想写一篇“如何用JS实现面向对象”,发现自己对prototype原型链还是有很多的不理解的地方。先看一张原型链关系图:
图片来自mollypages.org。
prototype是所有函数都有的一个属性。
function Man() {}
console.log(Man.prototype); // Object{}
prototype 属性使您有能力向对象添加属性和方法。在每个使用每个对象的属性或方法时,js会按照原型链的顺序查找属性,直到找到。
function employee(name,job,born) {
this.name=name;
this.job=job;
this.born=born;
}
var bill = new employee("Bill Gates","Engineer",1985);
employee.prototype.salary=null;
bill.salary=20000;
console.log(bill.salary); //20000
注意对象是没有prototype属性的,只有函数有。但是一些特有的浏览器(firefox,chrome)通过proto属性暴露了原型prototype,如上图。
new用于新建一个对象,例如:
function Man() {}
var m = new Man();
下面的代码用js模拟了new操作:
function newObj(Fun,arguments) {
var o = {};
if (Fun && typeof Fun === "function") {
o.__proto__ = Fun.prototype;
Fun.apply(o, arguments);
return o;
}
}
从代码中可以看出,首先新建一个对象o,然后修改proto指向Fun.prototype,然后以o为上下文(context)执行Fun函数,最后返回o。因为对象的proto设置是在new操作中的,所以导致了以下现象:
function Man() {}
function Father() {
this.name=""
}
var m = new Man();
Man.prototype = new Father();
console.log(m.name); // undefine
至此我们理解了图中的第一层,接下来讲第二、三层。
为何Foo.proto !== Foo.prptotype?
这里Foo函数可以看成是Function函数的对象!按照图中第一层的逻辑:对象的proto指向其函数的prototype属性,Foo的proto应该等于Function.prototype。
那么为什么Function函数和Object函数的proto都等于Function.prototype呢?
注意Function和Object都是函数,而所有的函数都是Function函数的对象(有点绕)!所以同上,它们的proto应该等于Function.prototype。
为什么o1与o2的proto等于Object.prototype呢?
原因与第一层的结构一样,o1,o2是Object函数的对象。
注意:Function.prototype与Foo.prototype同样是对象,它们也是通过Object函数构建的,所以它们的proto也等于Object.prototype。
Object.prototype值是无法修改,它提供了一些默认的方法。且它的proto等于null!
function Man(){
this.oo = "11";
}
Object.prototype = new Man();
console.log(Object.prototype.oo); //undefine
理解Javascript的原型链的重点在于对象、函数、函数的prototype,函数与函数的prototype同时也是对象。
在JavaScript语言中,所有对象的原型链根节点都是Object.prototype。
instanceof是一个二元运算符,如:A instanceof B. 其中,A必须是一个合法的JavaScript对象,B必须是一个合法的JavaScript函数 (function). 判断过程如下:
如果函数B在对象A的原型链 (prototype chain) 中被发现,那么instanceof操作符将返回true,否则返回false.
所以导致了:
Function instanceof Object; //true
Object instanceof Function; //true
Function instanceof Function; //true
Object instanceof Object; //true
这样的情况发生!