JavaScript学习笔记----- 继承的实现及其原理
按照自己在极客上学习的顺序整理了一下,参考了几位前辈的随笔,十分感谢: 参见http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt240
http://javapolo.iteye.com/blog/1996871
http://uule.iteye.com/blog/1158829
js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承有以下通用的几种方式
1、继承的第一种方式:原型链方式,实现原理即子类通过prototype将所有在父类中通过prototype追加的属性和方法都追加到Child,从而实现了继承。
弊端是不能直接实现多继承(多继承即一个子类可以有多个父类,它继承了多个父类的特性。)
function Person(){
}
Person.prototype.hello = "hello";
Person.prototype.sayHello = function(){
alert(this.hello);
}
function Child(){
}
Child.prototype = new Person();//这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追加到Child,从而实现了继承
Child.prototype.world = "world";
Child.prototype.sayWorld = function(){
alert(this.world);
}
var c = new Child();
c.sayHello();
c.sayWorld();// 这样既可以调用原型中的方法又可以调用新扩展的方法了
2.使用对象冒充实现继承(该种实现方式可以实现多继承)
实现原理:让父类的构造函数成为子类的方法,然后调用该子类的方法,通过this关键字给所有的属性和方法赋值(this关键字代表函数运行时,自动产生的一个内部对象)
unction Parent(username){
this.username = username;
this.hello = function(){
alert(this.username);
}
}
function Child(username,password){
//通过以下3行实现将Parent的属性和方法追加到Child中,从而实现继承
//第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对象,
//第二步:执行this.method方法,即执行Parent所指向的对象函数
//第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法
this.method = Parent;
this.method(username);//最关键的一行
delete this.method;
this.password = password;
this.world = function(){
alert(this.password);
}
}
var parent = new Parent("zhangsan");
var child = new Child("lisi","123456");
parent.hello();
child.hello();
child.world();
3、采用call方法改变函数上下文实现继承(该种方式不能继承原型链,若想继承原型链,则采用混合模式)
实现原理:改变函数内部的函数上下文this,使它指向传入函数的具体对象
call方法是Function类中的方法
call方法的第一个参数的值赋值给类(即方法)中出现的this
call方法的第二个参数开始依次赋值给类(即方法)所接受的参数
function test(str){
alert(this.name + " " + str);
}
var object = new Object();
object.name = "zhangsan";
test.call(object,"langsin");//此时,第一个参数值object传递给了test类(即方法)中出现的this,而第二个参数"langsin"则赋值给了test类(即方法)的str
function Parent(username){
this.username = username;
this.hello = function(){
alert(this.username);
}
}
function Child(username,password){
Parent.call(this,username);
this.password = password;
this.world = function(){
alert(this.password);
}
}
var parent = new Parent("zhangsan");
var child = new Child("lisi","123456");
parent.hello();//zhangsan
child.hello();//lisi
child.world();//123456
4、采用Apply方法改变函数上下文实现继承(该种方式不能继承原型链,若想继承原型链,则采用5混合模式)
实现原理:改变函数内部的函数上下文this,使它指向传入函数的具体对象
apply方法接受2个参数,
A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this
B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数
function Parent(username){
this.username = username;
this.hello = function(){
alert(this.username);
}
}
function Child(username,password){
Parent.apply(this,new Array(username));
this.password = password;
this.world = function(){
alert(this.password);
}
}
var parent = new Parent("zhangsan");
var child = new Child("lisi","123456");
parent.hello();
child.hello();
child.world();
Apply() Call()这两个方法基本上是一个意思,区别在于 call 的第二个参数可以是任意类型,而apply的第二个参数必须是数组,也可以是arguments
还有 callee,caller..
5、继承的第五种方式:混合方式
混合了call方式、原型链方式
function Parent(hello){
this.hello = hello;
}
Parent.prototype.sayHello = function(){
alert(this.hello);
}
function Child(hello,world){
Parent.call(this,hello);//将父类的属性继承过来
this.world = world;//新增一些属性
}
Child.prototype = new Parent();//将父类的方法继承过来
Child.prototype.sayWorld = function(){//新增一些方法
alert(this.world);
}
var c = new Child("zhangsan","lisi");
c.sayHello();
c.sayWorld();