针对什么是原型的疑问?我是这么理解:在使用构造函数创建对象(obj1)时,就会联系到另外一个对象(obj2),这个对象(obj2)就是对象(obj1)的原型。每一个对象都可以从原型那里继承属性和方法。
原型和实例的关系如下图:(原型与实例.png)
原生构造函数(Object(),Array(),Function()等)使用了prototype属性,方便让构造函数实例继承属性和方法。这就是JavaScript本身允许对象实例从构造函数的prototype属性继承属性和方法的机制。
每个函数都有一prototype的属性,也就是说,只有函数才会有prototype属性,如下:
function Fn(){};
Fn.prototype.name = "duxin";
var eg1 = new Fn();
console.log(eg1.name);
其中,通过new关键词创建的对象实例链接回到了它的构造函数Fn,而构造函数的prototype属性则是指向了一个对象。
任何对象都可以作为另一个对象的原型对象,用来共享属性。
把构造函数创建的实例连接到构造函数的prototype属性
原型链会把每个实例连接到它的构造函数的prototype属性,那么在使用new关键字由构造函数创建对象时,在创建的对象实例和构造函数之间的添加一个隐藏的链接__proto__。当构造函数被调用时,JavaScript后台会把所有原型连接起来,形成一个链。如下:
Array.prototype.foo = "foo";
var arr = new Array();
console.log(arr.__proto__.foo); //输出foo
console.log(Array.__proto__ === Array.__proto__) //true
主要用于跟踪从对象到该对象继承的原型对象的链接。
原型链的最后是Object.prototype。
因为prototype是一个对象,在原型链或者是查找中的最后一个是Object.prototype。如下代码:
var add = [];
console.log(add.foo);//undefined
在访问add未定义的属性foo时,就会查询原型链,先在add对象中查找foo属性,没有则在Array.prototype中查找。还是没有的话,最后在object.prototype中查找。三个地方都没有定义,则判定该属性是undefined。
在原型链中查找到并且返回的是第一个匹配结果。如下:
Object.prototype.name = "obj-duxin";
Array.prototype.name = "duxin-arr";
var add = [];
console.log(add.name);//duxin-arr
add.name = "add"
console.log(add.name);//add
这段代码中,Object.prototye.name是为属性设置默认的值。Array.prototype.name再次赋值就把设置的默认值给覆盖了。不管在原型链中的其他地方还有同样的属性名,在链中一旦找到属性就会结束。
使用新对象替换prototype属性会删除默认的构造函数属性
var Foo = function(){};
Foo.prototype = {};
var fooname = new Foo()
console.log(fooname.constructor === Foo);//false
console.log(fooname.constructor); //Object()
使用新对象替换prototype属性不会更新以前的实例,如下:
var Foo = function Foo(){};
Foo.prototype.x = 1;
var add = new Foo();
console.log(add.x); //1
Foo.prototype = {x:3};
console.log(add.x);//1
var ood = new Foo();
console.log(ood.x);//3