亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何分析JavaScript的繼承

發布時間:2022-01-19 09:02:40 來源:億速云 閱讀:148 作者:kk 欄目:web開發

這篇文章將為大家詳細講解有關如何分析JavaScript的繼承,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

原型鏈繼承

原理

本質是重寫原型對象,代之以一個新類型的實例。下面代碼中,原來存在于SuperType的實例對象的屬性和方法,現在也存在于SubType.prototype中了。

實現

function Super(){
    this.value = true;
}
Super.prototype.getValue = function(){
    return this.value
}
function Sub(){};
// Sub繼承了Super
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
const ins = new Sub();
console.log(ins.getValue()); // true

Sub繼承了Super,而繼承是通過創建Super實例,并將實例賦給Sub.prototype實現的。原來存在于Super的實例中的所有屬性和方法,現在也存在與Sub.prototype中。如圖所示。

如何分析JavaScript的繼承

上圖可以看出,沒有使用Sub默認提供的原型,而是給它換了一個新原型;這個新原型就是Super的實例。于是,新原型不僅具有作為一個Super的實例所擁有的屬性和方法,而且它還指向了Super的原型。最終結果就是這樣的:

ins=>Sub的原型=>Super的原型

getValue()方法仍然還在Sub.prototype中,但value屬性則位于Sub.prototype中。這是因為value是一個實例屬性,而getValue()則是一個原型方法。既然Sub.prototype現在是Super的實例,那么value位于該實例中。

此外,要注意ins.constructor現在指向的是 Super,這是因為原來 Sub.prototype 中的 constructor 被重寫了的緣故。

缺點

  • 私有原型屬性會被實例共享

  • 在創建子類型的實例時,不能向父類型的構造函數傳遞參數

原型鏈繼承最主要的問題:私有原型屬性會被實例共享,而這也正是為什么要在構造函數中,而不是原型對象中定義屬性的原因。在通過原型來實現繼承時,原型實例會變成另一個類的實例。于是,原先的實例屬性也就順理成章的變成了現在的原型屬性了。

function Super(){
    this.colors = ['red','green','blue'];
}
Super.prototype.getValue = function(){
    return this.colors
}
function Sub(){};
//Sub繼承了Super
Sub.prototype = new Super();
const ins1 = new Super();
ins1.colors.push('black');
console.log(ins1.colors);//['red','green','blue','black'];
const ins2 = new Sub();
console.log(ins2.colors);//['red','green','blue','black'];

原型鏈的第二個問題,在創建子類型的實例時,不能向父類型的構造函數傳遞參數。實際上,應該說是沒有辦法在不影響所有都想實例的情況下,給父類型的構造函數傳遞參數。再加上包含引用類型值的原型屬性會被所有實例共享的問題,在實踐中很少會單獨使用原型鏈繼承

注意問題

使用原型鏈繼承方法要謹慎地定義方法,子類型有時候需要重寫父類的某個方法,或者需要添加父類中不存在的某個方法。但不管怎樣,給原型添加方法的代碼一定要放在替換原型的語句之后。

function Super() {
    this.colors = ['red', 'green', 'blue'];
}
Super.prototype.getValue = function() {
    return this.colors
}
function Sub() {
    this.colors = ['black'];
};
//Sub繼承了Super
Sub.prototype = new Super();
//添加父類已存在的方法,會重寫父類的方法
Sub.prototype.getValue = function() {
    return this.colors;
}
//添加父類不存在的方法
Sub.prototype.getSubValue = function(){
    return false;
}
const ins = new Sub();
//重寫父類的方法之后得到的結果
console.log(ins.getValue()); //['black']
//在子類中新定義的方法得到的結果
console.log(ins.getSubValue());//false
//父類調用getValue()方法還是原來的值
console.log(new Super().getValue());//['red', 'green', 'blue']

借用構造函數繼承

原理

借用構造函數(有時候也叫做偽類繼承或經典繼承)。這種技術的基本思想相當簡單,即在子類構造函數的內部調用父類構造函數。別忘了,函數只不過是在特定環境中執行代碼的對象,因此通過使用apply()和call()方法也可以在新創建的對象上執行構造函數。

實現

function Super() {
    this.colors = ['red', 'green', 'blue'];
}
Super.prototype.getValue = function(){
    return this.colors;
}
function Sub(){
//繼承了Super
Super.call(this);//相當于把構造函數Super中的this替換成了ins實例對象,這樣在Super只有定義的私有屬性會被繼承下來,原型屬性中定義的公共方法不會被繼承下來
}
const ins = new Sub();
console.log(ins.colors);

傳遞參數:相對于原型鏈來講,借用構造函數繼承有一個很大的優勢,即可以在子類構造函數中向父類構造函數傳遞參數

function B(name){
    this.name = name;
}
function A(){
    //繼承了B,同時還傳遞了參數
    B.call(this,'ZZ');
    //實例屬性
    this.age = 100;
}
const p = new A();
alert(p.name);//'ZZ'
alert(p.age);//100

缺點

如果僅僅是借用構造函數,那么將無法避免構造函數模式存在的問題——方法都在構造函數中定義,因此函數復用就無從談起。而且,在父類的原型中定義的方法,對子類而言是不可見的,所以這種方式使用較少。

組合繼承

原理

組合繼承,指的是將原型鏈和借用構造函數技術組合到一起,從而發揮兩者之長的一種繼承模式。其背后的思想是使用原型鏈實現對原型上的公共屬性和方法的繼承,而通過借用構造函數繼承來實現對父類私有屬性的繼承。這樣,即通過在父類原型上定義方法實現了函數復用,又能夠保證每個實例都有父類的私有屬性。

實現

function Super(name){
    this.name = name;
    this.colors = ['red','blue','green'];
}
Super.prototype.sayName = function(){
    alert(this.name);
}
function Sub(name,age){
    Super.call(this,name);
    this.age = age;
}
// 繼承方法
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
Sub.prototype.sayAge = function(){
    alert(this.age);
}
const ins = new Sub('jarvis',18);
ins.colors.push('black');
console.log(ins.colors);// ["red", "blue", "green", "black"]
ins.sayName();//'jarvis'
ins.sayAge();//18
const ins2 = new Sub('ershiyi',21);
console.log(ins2.colors);//["red", "blue", "green"]
ins2.sayName();//'ershiyi'
ins2.sayAge();//21

在上個例子中,Sub構造函數定義了兩個屬性:name和age。Super的原型定義了一個sayName()方法。在Sub構造函數中調用Super構造函數時傳入了name參數,緊接著又定義它自己的屬性age。然后,將Super的實例賦值給Sub的原型,然后又在該新原型上定義了方法sayAge()。這樣一來,就可以讓不同的Sub實例分別擁有自己的屬性——包括colors屬性,又可以使用相同的方法組合繼承避免了原型鏈和借用構造函數的缺陷,融合了他們的優點,稱為JavaScript中最常用的繼承模式。

缺點

無論在什么情況下,都會調用兩次父類的構造函數:一次是在創建子類原型的時候,另一次是在子類構造函數內部。

寄生組合式繼承

原理

組合繼承是JavaScript最常用的繼承模式;不過,它也有自己的不足。組合繼承最大的問題就是無論什么情況下,都會調用兩次父類構造函數:一次是在創建子類原型的時候,另一次是在子類構造函數內部。沒錯,子類型最終會包含超類型對象的全部實例屬性,但不得不在調用子類型構造函數時重寫這些屬性。再來看一看下面組合繼承的例子。

實現

function Super(name){
    this.name = name;
    this.colors = ['red','blue','green'];
}
Super.prototype.sayName = function(){
    alert(this.name);
}
function Sub(name,age){
    Super.call(this,name);
    this.age = age;
}
// 繼承方法
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
Sub.prototype.sayAge = function(){
    alert(this.age);
}
const ins = new Sub('jarvis',18);
ins.colors.push('black');
console.log(ins.colors);// ["red", "blue", "green", "black"]
ins.sayName();//'jarvis'
ins.sayAge();//18
const ins2 = new Sub('ershiyi',21);
console.log(ins2.colors);//["red", "blue", "green"]
ins2.sayName();//'ershiyi'
ins2.sayAge();//21

所謂寄生組合式繼承,即通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。其背 后的基本思路是:不必為了指定子類型的原型而調用超類型的構造函數,所需要的無非就是超類型原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,然后再將結果指定給子類型的原型。寄生組合式繼承的基本模式如下所示。

function Super(name){
    this.name = name;
    this.colors = ['red','blue','green'];
}
Super.prototype.sayName = function(){
    alert(this.name);
}
function Sub(name,age){
    //繼承實例屬性
    Super.call(this,name);
    this.age = age;
}
// 繼承公有的方法
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.sayAge = function(){
    alert(this.age);
}
const ins = new Sub('jarvis',18);
ins.colors.push('black');
console.log(ins.colors);// ["red", "blue", "green", "black"]
ins.sayName();//'jarvis'
ins.sayAge();//18
const ins2 = new Sub('ershiyi',21);
console.log(ins2.colors);//["red", "blue", "green"]
ins2.sayName();//'ershiyi'
ins2.sayAge();//21

多重繼承

JavaScript中不存在多重繼承,那也就意味著一個對象不能同時繼承多個對象,但是可以通過變通方法來實現。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>18 多重繼承</title>
</head>
<body>
<script type="text/javascript">
// 多重繼承:一個對象同時繼承多個對象
// Person  Parent  Me
function Person(){
this.name = 'Person';
}
Person.prototype.sayName = function(){
console.log(this.name);
}
// 定制Parent
function Parent(){
this.age = 30;
}
Parent.prototype.sayAge = function(){
console.log(this.age);
}
function Me(){
// 繼承Person的屬性
Person.call(this);
Parent.call(this);
}
// 繼承Person的方法
Me.prototype = Object.create(Person.prototype);
// 不能重寫原型對象來實現 另一個對象的繼承
// Me.prototype = Object.create(Parent.prototype);
// Object.assign(targetObj,copyObj)
Object.assign(Me.prototype,Parent.prototype);
// 指定構造函數
Me.prototype.constructor = Me;
const me = new Me();
</script>
</body>
</html>

ES5 與 ES6 繼承差異

在 ES5 的傳統繼承中, this 的值會先被派生類創建,隨后基類構造器才被調用。這意味著 this 一開始就是派生類的實例,之

后才使用了基類的附加屬性對其進行了裝飾。

在 ES6 基于類的繼承中, this 的值會先被基類創建,隨后才被派生類的構造 器所修改。結果是 this 初始就擁有作為基類的內置對象的所有功能,并能正確接收與之關聯的所有功能。

JavaScript是什么

JavaScript是一種直譯式的腳本語言,其解釋器被稱為JavaScript引擎,是瀏覽器的一部分,JavaScript是被廣泛用于客戶端的腳本語言,最早是在HTML網頁上使用,用來給HTML網頁增加動態功能。

關于如何分析JavaScript的繼承就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

景东| 东安县| 伊春市| 左贡县| 南涧| 临西县| 句容市| 普陀区| 霸州市| 兴安县| 平江县| 乐陵市| 滦平县| 梅州市| 九台市| 谢通门县| 陆河县| 高邑县| 汕头市| 嘉峪关市| 灵武市| 永新县| 洪雅县| 固镇县| 红原县| 维西| 唐海县| 巴林左旗| 卢湾区| 拜泉县| 琼海市| 呈贡县| 县级市| 读书| 台湾省| 青铜峡市| 桃园县| 泾源县| 托里县| 郴州市| 江源县|