首先來看一段代碼:
function Person(){
}
function Student(){
}
Student.prototype = Person.prototype;//第一種方式
Student.prototype = new Person();//第二種方式
Student.prototype = Object.create(Person.prototype)//第三種方式
第一種方式(不可取):
可以實現繼承,但是在改變Student的同時也會相應的改變Person,這很顯然不是我們所需要的,所以此種繼承方案不可取,是錯誤的。
第二種方式(原型繼承):
new Person()調用構造函數得到了一個Person的實例,並且這個實例指向了Person的prototype,所以這裏實現了繼承。但是就是因爲調用了構造函數,所以這樣可能會有問題,比如說,Person的構造函數是需要傳遞參數的function Person(name,age)等,那麼在實例化的時候需要傳遞什麼參數進去呢?很顯然,不管傳遞什麼都是很彆扭的,所以此種方案使用的也不多。
第三種方式(Object.ceate):
此方案是最爲理想的方案。使用Object.create()方法創建一個空的對象,並且這個對象的原型指向了Person.prototype,這樣我們既保證了我們可以繼承Person.prototype上面的方法,並且Student.prototype又有自己的一個空的對象,所以Student的修改不會影響到原型鏈上面的方法。
但是這裏也有一個問題,就是Object.create()方法是在ES5之後纔有的方法,那麼在之前的版本我們可以用另一個方法來模擬一下代替:
if(!Object.create){
Object.create = function(proto){
funtion F(){} //臨時的空函數
F.prototype = proto; //將空函數的prototype屬性複製給我們想要作爲原型的對象
return new F; //new一個構造器,那麼就會創建一個對象,這個對象的原型指向構造器的prototype
}
}
另外還有一種方式,使用call和apply:
function Person(name,age,love){
this.name=name;
this.age=age;
this.love=love;
this.say=function say(){
alert("姓名:"+name);
}
}
//call方式
function student(name,age){
Person.call(this,name,age);
}
//apply方式
function teacher(name,love){
Person.apply(this,[name,love]);
//Person.apply(this,arguments); //跟上句一樣的效果,arguments
}
//call與aplly的異同:
//1,第一個參數this都一樣,指當前對象
//2,第二個參數不一樣:call的是一個個的參數列表;apply的是一個數組(arguments也可以)