本文目錄一覽:
關於JS實現繼承的方法都有哪一些?
定義一個父類:
// 定義一個動物類
function Animal (name) {
// 屬性
this.name = name || ‘Animal’;
// 實例方法
this.sleep = function(){
console.log(this.name + ‘正在睡覺!’);
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + ‘正在吃:’ + food);
1.原型鏈繼承
核心:將父類的實例作為子類的原型
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = ‘cat’;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat(‘fish’));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
特點:
1.非常純粹的繼承關係,實例是子類的實例,也是父類的實例
2.父類新增的原型方法、屬性,子類都能訪問到
3.簡單,易於實現
缺點:
1.要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之後執行
(可以在cat構造函數中,為Cat實例增加實例屬性)
2.無法實現多繼承
3.來自原型對象的引用屬性被所有實例共享
4.創建子類實例時,無法向父類構造函數傳參
下面代碼解釋缺點3(注意是引用屬性):
function Super(){
this.val = 1;
this.arr = [1];
}
function Sub(){
// …
}
Sub.prototype = new Super(); // 核心
var sub1 = new Sub();
var sub2 = new Sub();
sub1.val = 2;
sub1.arr.push(2);
alert(sub1.val); // 2
alert(sub2.val); // 1
alert(sub1.arr); // 1, 2
alert(sub2.arr); // 1, 2
2.構造繼承
核心:使用父類的構建函數來增強子類實例,等於複製父類的實例屬性給子類(沒用到原型),除了call方法,也可以用apply()
function Cat(name){
Animal.call(this);
this.name = name || ‘Tom’;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
特點:
1.解決了1中,子類實例共享父類引用屬性的問題
2.創建子類實例時,可以向父類傳遞參數
3.可以實現多繼承(call多個父類對象)
缺點:
1.實例並不是父類的實例,只是子類的實例
2.只能繼承父類的實例屬性和方法,不能繼承原型屬性和方法
3.無法實現函數復用,每個子類都有父類的實例函數的副本,影響性能
3.實例繼承
核心:為父類實例添加新特性,作為子類實例返回
function Cat(name){
var instance = new Animal();
instance.name = name || ‘Tom’;
return instance;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
特點:
1.不限制調用方式,不管是new 子類()還是子類(),返回的對象都具有相同的效果
缺點:
1.實例是父類的實例,不是子類的實例
2.不支持多繼承
4. 拷貝繼承
核心:使用for…in將父類實例中的方法賦給子類實例
unction Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || ‘Tom’;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
特點:
1.支持多繼承
缺點:
1.效率較低,內存佔用高(因為要拷貝父類的屬性)
2.無法獲取父類不可枚舉的方法(for in無法訪問不可枚舉的方法)
5.組合繼承
核心:通過調用父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類實例作為子類原型,實現函數復用
function Cat(name){
Animal.call(this);
this.name = name || ‘Tom’;
}
Cat.prototype = new Animal();
//組合繼承需要修復構造函數的指向
Cat.prototype.constructor=Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
特點:
1.彌補了方式2的缺陷,可以繼承實例屬性、方法,也可以繼承原型屬性、方法
2.既是子類的實例,也是父類的實例
3.不存在引用屬性的共享問題
4.可傳參
5.函數可復用
缺點:
1.調用了兩次父類構造函數,生成了兩份實例(子類實例將子類原型上的那份屏蔽了)
6.寄生組合繼承
核心:通過寄生方式,砍掉父類的實例屬性,這樣,在調用兩次父類的構造的時候,就不會初始化兩次實例方法/屬性,避免的組合繼承的缺點
function Cat(name){
Animal.call(this);
this.name = name || ‘Tom’;
}
(function(){
// 創建一個沒有實例方法的類
var Super = function(){};
Super.prototype = Animal.prototype;
//將實例作為子類的原型
Cat.prototype = new Super();
//寄生組合繼承需要修復構造函數的指向
Cat.prototype.constructor=Cat;
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
特點:
1.堪稱完美
缺點:
1.實現較為複雜 (BY三人行慕課)
JS中關於繼承的幾種方式
1、原型鏈繼承
2、構造繼承
3、實例繼承
4、拷貝繼承
5、組合繼承
6、寄生組合繼承
js繼承之組合繼承
組合繼承,指的是將原型鏈和借用構造函數的技術組合在一塊,從而發揮二者之長的一種繼承模式。
紅寶書是這樣說的,其思路是使用原型鏈實現對原型屬性和方法的繼承,通過借用構造函數來實現對實例屬性的繼承,這樣,即通過在原型上定義方法實現了函數復用,又能保證每個實例都有自己的屬性。
下面我們看一個組合繼承的例子,沒有女朋友我們就new一個女朋友
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優點,So,組合繼承成為了JavaScript中最常用的繼承模式。
js中繼承的幾種用法總結
一,js中對象繼承
js中有三種繼承方式
1.js原型(prototype)實現繼承
複製代碼 代碼如下:
SPAN style=”BACKGROUND-COLOR: #ffffff”SPAN style=”FONT-SIZE: 18px”html
body
script type=”text/javascript”
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.sayHello=function(){
alert(“使用原型得到Name:”+this.name);
}
var per=new Person(“馬小倩”,21);
per.sayHello(); //輸出:使用原型得到Name:馬小倩
function Student(){}
Student.prototype=new Person(“洪如彤”,21);
var stu=new Student();
Student.prototype.grade=5;
Student.prototype.intr=function(){
alert(this.grade);
}
stu.sayHello();//輸出:使用原型得到Name:洪如彤
stu.intr();//輸出:5
/script
/body
/html/SPAN/SPAN
2.構造函數實現繼承
複製代碼 代碼如下:
SPAN style=”FONT-SIZE: 18px”html
body
script type=”text/javascript”
function Parent(name){
this.name=name;
this.sayParent=function(){
alert(“Parent:”+this.name);
}
}
function Child(name,age){
this.tempMethod=Parent;
this.tempMethod(name);
this.age=age;
this.sayChild=function(){
alert(“Child:”+this.name+”age:”+this.age);
}
}
var parent=new Parent(“江劍臣”);
parent.sayParent(); //輸出:“Parent:江劍臣”
var child=new Child(“李鳴”,24); //輸出:“Child:李鳴 age:24”
child.sayChild();
/script
/body
/html/SPAN
3.call , apply實現繼承
複製代碼 代碼如下:
SPAN style=”FONT-SIZE: 18px”html
body
script type=”text/javascript”
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也可以)
var per=new Person(“武鳳樓”,25,”魏熒屏”); //輸出:“武鳳樓”
per.say();
var stu=new student(“曹玉”,18);//輸出:“曹玉”
stu.say();
var tea=new teacher(“秦傑”,16);//輸出:“秦傑”
tea.say();
/script
/body
/html/SPAN
二、call和apply的用法(詳細介紹)
js中call和apply都可以實現繼承,唯一的一點參數不同,func.call(func1,var1,var2,var3)對應的apply寫法為:func.apply(func1,[var1,var2,var3])。
JS手冊中對call的解釋:
複製代碼 代碼如下:
SPAN style=”FONT-SIZE: 18px”call 方法
調用一個對象的一個方法,以另一個對象替換當前對象。
call([thisObj[,arg1[, arg2[, [,.argN]]]]])
參數
thisObj
可選項。將被用作當前對象的對象。
arg1, arg2, , argN
可選項。將被傳遞方法參數序列。
說明
call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。
如果沒有提供 thisObj 參數,那麼 Global 對象被用作 thisObj。/SPAN
說簡單一點,這兩函數的作用其實就是更改對象的內部指針,即改變對象的this指向的內容。這在面向對象的js編程過程中有時是很有用的。下面以apply為例,說說這兩個函數在 js中的重要作用。如:
複製代碼 代碼如下:
SPAN style=”FONT-SIZE: 18px” function Person(name,age){ //定義一個類
this.name=name; //名字
this.age=age; //年齡
this.sayhello=function(){alert(this.name)};
}
function Print(){ //顯示類的屬性
this.funcName=”Print”;
this.show=function(){
var msg=[];
for(var key in this){
if(typeof(this[key])!=”function”){
msg.push([key,”:”,this[key]].join(“”));
}
}
alert(msg.join(” “));
};
}
function Student(name,age,grade,school){ //學生類
Person.apply(this,arguments);//比call優越的地方
Print.apply(this,arguments);
this.grade=grade; //年級
this.school=school; //學校
}
var p1=new Person(“卜開化”,80);
p1.sayhello();
var s1=new Student(“白雲飛”,40,9,”嶽麓書院”);
s1.show();
s1.sayhello();
alert(s1.funcName);/SPAN
另外,Function.apply()在提升程序性能方面有着突出的作用:
我們先從Math.max()函數說起,Math.max後面可以接任意個參數,最後返回所有參數中的最大值。
比如
複製代碼 代碼如下:
SPAN style=”FONT-SIZE: 18px”alert(Math.max(5,8)); //8
alert(Math.max(5,7,9,3,1,6)); //9
//但是在很多情況下,我們需要找出數組中最大的元素。
var arr=[5,7,9,1];
//alert(Math.max(arr)); // 這樣卻是不行的。NaN
//要這樣寫
function getMax(arr){
var arrLen=arr.length;
for(var i=0,ret=arr[0];iarrLen;i++){
ret=Math.max(ret,arr[i]);
}
return ret;
}
alert(getMax(arr)); //9
//換用apply,可以這樣寫
function getMax2(arr){
return Math.max.apply(null,arr);
}
alert(getMax2(arr)); //9
//兩段代碼達到了同樣的目的,但是getMax2卻優雅,高效,簡潔得多。
//再比如數組的push方法。
var arr1=[1,3,4];
var arr2=[3,4,5];
//如果我們要把 arr2展開,然後一個一個追加到arr1中去,最後讓arr1=[1,3,4,3,4,5]
//arr1.push(arr2)顯然是不行的。 因為這樣做會得到[1,3,4,[3,4,5]]
//我們只能用一個循環去一個一個的push(當然也可以用arr1.concat(arr2),但是concat方法並不改變arr1本身)
var arrLen=arr2.length;
for(var i=0;iarrLen;i++){
arr1.push(arr2[i]);
}
//自從有了Apply,事情就變得如此簡單
Array.prototype.push.apply(arr1,arr2); //現在arr1就是想要的結果/SPAN
原創文章,作者:NTSS,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/139803.html