function Son() {
this.name = 'a';
this.names = ['a'];
}
var son1 = new Son();
son1.name = 'b';
son1.names.push('b');
var son2 = new Son();
console.log(son2.name); //a
console.log(son2.names); //a
可以看出,实例属性是副本
function Son() {
}
Son.prototype.name='a';
Son.prototype.names=['a'];
var son1 = new Son();
son1.name = 'b';
son1.names.push('b');
var son2 = new Son();
console.log(son2.name); //a
console.log(son2.names); //a,b
这里把name和names改成原型属性,发现原型属性中基本类型name是副本,而引用类型names的值变化了。
那么在不知道是否是基本类型的属性还是引用类型的属性,只记住实例属性是不变化的。
我们可以这么操作
再试试函数
function Son() {
this.print = function() {
console.log('a');
}
}
var son1 = new Son();
son1.print = function() {
console.log('b');
}
var son2 = new Son();
son2.print();//a
function Son() {}
Son.prototype.print = function() {
console.log('a');
}
var son1 = new Son();
son1.print = function() {
console.log('b');
}
var son2 = new Son();
son2.print();//a
说明方法互不影响。
再试试原型继承
function Father(){
this.name='a';
this.names=['a'];
}
function Son(){
}
Son.prototype=new Father();
var son1=new Son();
var son2=new Son();
son1.name='b';
son1.names.push('b');
console.log(son2.name);//a
console.log(son2.names);//a,b
var father=new Father();
console.log(father.name);//a
console.log(father.names);//a
//子类之间互相影响
function Father() {}
Father.prototype.name = 'a';
Father.prototype.names = ['a'];
function Son() {}
Son.prototype = new Father();
var son1 = new Son();
var son2 = new Son();
son1.name = 'b';
son1.names.push('b');
//var son2 = new Son();//将声明放在属性修改之后,结果仍旧一样
console.log(son2.name); //a
console.log(son2.names); //a,b
var father = new Father();
console.log(father.name); //a
console.log(father.names); //a,b
//说明子类还能修改了父类的原型属性中的引用属性
function Father() {
this.print = function() {
console.log('a');
}
}
function Son() {}
Son.prototype = new Father();
var son1 = new Son();
var son2 = new Son();
son1.print = function() {
console.log('b');
}
son2.print();//a
var father = new Father();
father.print();//a
function Father() {}
Father.prototype.print = function() {
console.log('a');
}
function Son() {}
Son.prototype = new Father();
var son1 = new Son();
var son2 = new Son();
son1.print = function() {
console.log('b');
}
son2.print(); //a
var father = new Father();
father.print(); //a
这么看来,原型链继承方式,构造函数的实例属性是独立的。其它的会互相影响。在无法区份到底是基本数据类型还是引用类型,只考虑实例属性的稳定性。方法则互不影响。
1.子类的原型属性中的引用类型互相影响,Son.prototype.names=['a']
2.子类从父类继承来的实例属性中的引用属性会互相影响
组合模式中,子类从父类继承的属性是实例属性。
组合继承中,父类(超类)的属性必须是实例属性,才能在call或者apply中进行调用。而方法则无所谓。我们试一下方法放在构造函数中,看能否继承和修改。
function Father() {
this.print = function() {
console.log('a');
}
}
function Son() {
Father.call(this);
}
Son.prototype = new Father();
var son1 = new Son();
var son2 = new Son();
son1.print(); //a
son1.print = function() {
console.log('b');
}
son1.print(); //b
son2.print(); ///a
var father = new Father();
father.print(); //a
再尝试一下
function Father() {}
Father.prototype.print = function() {
console.log('a');
}
function Son() {
Father.call(this);
}
Son.prototype = new Father();
var son1 = new Son();
var son2 = new Son();
son1.print(); //a
son1.print = function() {
console.log('b');
}
son1.print(); //b
son2.print(); ///a
var father = new Father();
father.print(); //a
我们现在看一下Son.prototype.constructor = Son这个到底做了什么。
function Son() {}
console.log(Son === Son.prototype.constructor); //true
function Father() {};
Son.prototype = new Father();
console.log(Son === Son.prototype.constructor); //false
可以看到,原型继承的过程中,constructor不在指向原有的构造函数。
那么试试构造函数继承
function Father() {};
function Son() {
Father.apply(this);
}
console.log(Son === Son.prototype.constructor); //true
不受影响