function MyObject(){}; var obj1 = new MyObject(); MyObject.prototype.type = 'myObject'; MyObject.prototype.value = "aa"; var obj2 = new MyObject(); MyObject.prototype = { constructor: 'MyObject', type: 'Brid', value:'bb' }; var obj3 = new MyObject(); // 显示对象的属性 alert(obj1.type); // myObject alert(obj2.type); // myObject alert(obj3.type); // Brid
如上代码:obj1与obj2两个实例是指向同一个原型的,obj3通过修改原型后,指向与新的构造函数的原型;如下测试代码:
// 显示实例的关系 alert(obj1 instanceof MyObject); // false alert(obj2 instanceof MyObject); // false alert(obj3 instanceof MyObject); // true
我们可能会有误解,为什么obj1 与 obj2不是MyObject的实例呢?我们从代码中确实可以看到,他们2个实例确实是MyObject的实例,那为什么现在不是呢?那我们现在再来看看对象实例constructor属性,如下测试代码:
复制代码 代码如下:
console.log(obj1 instanceof obj1.constructor); // false
console.log(obj1.constructor === MyObject); // true
第一行打印false,可以看出 该对象obj1不是 obj1.constructor构造器,第二行打印true,obj1.constructor的构造器还是指向与MyObject对象;如下三行代码:
复制代码 代码如下:
alert(obj1 instanceof MyObject); // false
console.log(obj1 instanceof obj1.constructor); // false
console.log(obj1.constructor === MyObject); // true
从上面的三行代码我们可以总结出,原型被重写后,obj1.constructor的构造器还是指向与MyObject,但是obj1不是obj1.constructor的构造器的实例,那就是说obj1不是MyObject的实例;
在javascript中,一个构造器的原型可以被重写,那就意味着之前的一个原型被废弃,在该构造器实例中:
1.旧的实例使用这个被废弃的原型,并受该原型的影响。
2.新创建的实例则使用重写后的原型,受新原型的影响。
理解构造器重写
上面我们了解了原型被重写,下面我们来讲解下构造器被重写,继承待会再来研究,我们先来看看构造器的重写demo,代码如下:
function MyObject(){}; var obj1 = new MyObject(); MyObject = function(){}; var obj2 = new MyObject(); console.log(obj1 instanceof MyObject); // false console.log(obj2 instanceof MyObject); // true console.log(obj1 instanceof obj1.constructor); // true
如上代码 obj1实例化出来对象被下面的MyObject构造器重写了,因此obj1不是MyObject的实例,obj2才是MyObject的实例,那obj1为什么是obj1.constructor的实例呢?说明构造器的重写不会影响实例的继承关系。
上面的构造器重写MyObject不是具名函数,下面我们再来看看具名函数的重写,代码如下:
function MyObject(){}; var obj1 = new MyObject(); function MyObject(){}; var obj2 = new MyObject(); console.log(obj1 instanceof MyObject); // true console.log(obj2 instanceof MyObject); // true console.log(obj1 instanceof obj1.constructor); // true
如上代码;从上面代码结构来看,obj1与obj2是2个不同的MyObject()构造器的实例,但是从逻辑上看,后面的MyObject()构造器其实是覆盖了前面的构造器,所以obj1与obj2都是第二个MyObject的构造器的实例;
因此上面打印的都是true;
原型对象的缺点:
1.省略了构造函数传递参数,所有实例在默认情况下都取得相同的属性值和方法,这并不好,比如我想A实例不需要自己的属性值,B实例需要有自己的属性值和自己的方法,那么原型对象就不能够满足需求;
2.原型最大的好处就是可以共享属性和方法,但是假如我给A实例化后添加一个方法后,我不想给B实例化添加对应的方法,但是由于原型都是共享的,所以在B实例后也有A中添加的方法;
对应第二点,我们可以看如下demo:
function Dog(){}; Dog.prototype = { constructor: Dog, name: 'aa', values: ["aa",'bb'], say: function(){ alert(this.name); } } var dog1 = new Dog(); dog1.values.push("cc"); console.log(dog1.values); // ["aa","bb","cc"] var dog2 = new Dog(); console.log(dog2.values); // ["aa","bb","cc"]
如上代码,我给实例化dog1的values再添加一个值为cc后,那么原型就变成
[“aa”,”bb”,”cc”]后,如果现在再实例化dog2后,那么继续打印dog2.values的值也一样为[“aa”,”bb”,”cc”];
理解组合使用构造函数模式和原型模式