javascript对象继承

一、实例化和继承的区别

构造函数、原型和实例的关系:每 个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型 对象的内部指针。

类(Class)和实例(Instance),类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

eg: function a(){};
var instance = new a();
//new原理:
var obj={};
obj._proto_ = a.prototype;
a.call(this);
return obj

  

eg2:function Point(x, y) { this.x = x; this.y = y; }
Point.prototype = {
  print: function () { console.log(this.x, this.y); }
};
var p = new Point(10, 20);
p.print(); // 10 20

实例即将构造函数执行并赋予特定的值。通过new fn()新建的对象即为fn的实例。

实例化即为新建一个对象并指向构造函数原型,并且在这个对象作用域内执行构造函数。

继承即复用父对象的方法和属性并且自己可以重写方法和新建属性和方法。

所以实例就是继承了构造函数方法和属性的对象。但是它不能重写和新建新的方法和属性,只能用构造函数及构造函数原型上有的。

但是继承要求必须做到以上两点。

所以继承需要在实例化的基础上做其他必要的处理。

如果单纯的使用实例来处理继承:(原型式继承)

Object.create(obj,{})第二个参数和Object.defineproperty(obj,{})的第二个参数类似。

Object.create(obj,{})的原理:

function F(){};
F.prototype = obj;
return new F();

即返回一个F的实例,F的原型指向obj,即F的实例的原型指向F的原型即指向obj

从本质上讲,Object.create()对传入其中的对象执行了一次浅复制

eg:
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

对于引用类属性,两个实例同时指向此地址,此属性成为两个实例的公用属性。

在没有必要兴师动众地创建构造函数,而只想让一个对象与另一个对象保持类似的情况下,原型式 继承是完全可以胜任的。不过别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模 式一样。

-----------------------------------------------

借用构造函数继承

,在子类中直接执行父类构造函数。可以在子类型构造函数中向超类型构造函 数传递参数
function SuperType(name){
this.name = name;
}
function SubType(){
//继承了 SuperType,同时还传递了参数
SuperType.call(this, "Nicholas");
//实例属性
this.age = 29;
}
var instance = new SubType();
alert(instance.name); //"Nicholas";
alert(instance.age); //29

构造函数模式存在的问题——方法都在构造函数中定 义,因此函数复用就无从谈起了。而且,在超类型的原型中定义的方法,对子类型而言也是不可见的,结 果所有类型都只能使用构造函数模式。

组合继承(最常用的继承模式)

function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
//继承属性 
SuperType.call(this, name); this.age = age; } //继承方法 SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); instance1.sayName(); instance1.sayAge(); //"red,blue,green,black" //"Nicholas"; //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); instance2.sayName(); instance2.sayAge(); //"red,blue,green" //"Greg"; //27

SuperType 构造函数定义了两个属性:name 和 colors。SuperType 的原型定义 了一个方法 sayName()。SubType 构造函数在调用 SuperType 构造函数时传入了 name 参数,紧接着 又定义了它自己的属性 age。然后,将 SuperType 的实例赋值给 SubType 的原型,然后又在该新原型 上定义了方法 sayAge()。这样一来,就可以让两个不同的 SubType 实例既分别拥有自己属性——包 括 colors 属性,又可以使用相同的方法了。

寄生组合式继承是引用类型最理想的继承范式

即将上面的第二次调用构造函数继承方法的new改为如下

function inheritPrototype(subType, superType){
var prototype = object(superType.prototype);//创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype;//指定对象
}

也可改为subType.prototype = Object.create(superType.prototype);不过这样和直接new并无区别,而且速度还慢。

在上面函数中第二句增强函数也可以去掉,因为并不影响,原型链。constuctor即由原型指向构造函数。