有关JS的继承

    在JS中继承是一个非常复杂的话题,比其他任何面向对象语言中的继承都复杂得多。在大多数其他面向对象语言中,继承一个类只需使用一个关键字即可。在JS中想要达到继承公用成员的目的,需要采取一系列措施。
 
    Js的继承在很多书里面细致的分了很多种类型和实现方式,大体上就是两种:对象冒充、原型方式。这两种方式各有优点和缺陷。
对象冒充继承:
【优点】可以实现多重继承;
【缺点】无法继承prototype域的变量和方法;
        所有的成员方法都是针对this而创建的,所有的实例都会拥有一份成员方法的副本,属于深copy,比较浪费资源
 
原型继承:
【优点】所有实例共用一个pototype域,性能好些;
【缺点】不能传递参数;
        注意 constructor 会指向父对象;

 
我们来列举一些出来看看:
 
(一)对象冒充:
function Parent(name) {
	this.name = name;
	this.showName = function () {
		console.log(this.name);
	};
};

function Child (name, age) {
	this.method = Parent;
	this.method(name);
	delete this.method;
	
	this.age = age;
	this.showAge = function () {
		console.log(this.name +":"+ this.age);
	};
};

var parent = new Parent("Kang"),
	child = new Child("F7", 30);

parent.showName();
child.showName();
child.showAge();
    注意这里的上下文环境中的this对象是Child 的实例,所以在执行Parent构造函数脚本时,所有Parent的变量和方法都会赋值给this所指的对象,即Child的实例,这样子就达到Child继承了Parent的属性方法的目的。之后删除临时引用method,是防止维护Child中对Parent的类对象(注意不是实例对象)的引用更改,因为更改method会直接导致类Parent(注意不是类Parent的对象)结构的变化。
 
(小插曲)
    在Js版本更新的过程中,为了更方便的执行这种上下文this的切换以达到继承或者更加广义的目的,增加了call和apply函数。它们的原理是一样的,只是参数不同的版本罢了(一个可变任意参数,一个必须传入数组作为参数集合)。
关于Call方法,官方解释:调用一个对象的一个方法,以另一个对象替换当前对象。 
call (thisOb,arg1, arg2…)
下面我们将借助call和apply方法实现继承。
 
(二)call方法继承:
function ParentCall (name) {
	this.name = name;
	this.showName = function () {
		console.log(this.name);
	};
};

function ChildCall (name, age) {
	ParentCall.call(this, name);
	this.age = age;
	this.showAge = function () {
		console.log(this.name +":"+ this.age);
	};
};
var pc = new ParentCall("Kang"),
	cc = new ChildCall("F7", 30);

pc.showName();
cc.showName();
cc.showAge();
 
(三)apply方法继承:
function ParentApply (name) {
	this.name = name;
	this.showName = function () {
		console.log(this.name);
	};
};

function ChildApply (name, age) {
	ParentApply.apply(this, [name]);
	this.age = age;
	this.showAge = function () {
		console.log(this.name +":"+ this.age);
	};
};
var pa = new ParentApply("Kang"),
	ca = new ChildApply("F7", 30);

pa.showName();
ca.showName();
ca.showAge();
 
以上的 call 和 apply 方法继承都是对象冒充原理的一个运用。
 
(四)原型继承:
function ParentPrototype () {
	this.name = "F7";// 不能传递参数就只能写常量了
	this.showName = function () {
		console.log(this.name);
	}
};
ParentPrototype.prototype.showInfo = function () {
	console.log(this.name +":"+ this.age); 
};

function ChildPrototype () {
	this.age = 30;
};
ChildPrototype.prototype = new ParentPrototype();

var ap = new ChildPrototype(),
	bp = new ParentPrototype();

bp.showName();
ap.showName();
ap.showInfo();
 
(五)混合集成【寄生组合模式】:
    为了集合两种继承模式的优点,消除缺点产生了这种混合模式。
    利用对象冒充机制的call方法把父类的属性给抓取下来,而成员方法尽量写进被所有对象实例共享的prototype域中,以防止方法副本重复创建。然后利用原型继承让子类继承父类prototype域的所有方法。
function ParentBlend (name) {
	this.name = name;
	this.showName = function () {
		console.log(this.name);
	};
};
ParentBlend.prototype.showInfo = function () {
	console.log(this.name);
};

function ChildBlend (name, age, sex) {
	ParentBlend.call(this, name);
	this.age = age;
	this.sex = sex
	this.showAge = function () {
		console.log(this.name +":"+ this.age);
	};
};
ChildBlend.prototype = new ParentBlend();
ChildBlend.prototype.showSex = function () {
	console.log(this.name +":"+ this.sex);
};

var pb = new ParentBlend("Kang"),
	cb = new ChildBlend("F7", 30, "男");

pb.showName();
pb.showInfo();
cb.showName();
cb.showInfo();
cb.showAge();
cb.showSex();

One Response to “有关JS的继承”

  1. www.452470.com.cn说道:

    博主好厉害!