首頁 web前端 js教程 JavaScript程式中實作繼承特性的方式(圖文教學)

JavaScript程式中實作繼承特性的方式(圖文教學)

May 21, 2018 am 09:33 AM
javascript js

JavaScript是一門強行聲稱物件導向的語言,而繼承是物件導向的一大主要特性,以下是我給大家整理的,有興趣的同學可以去看看。

概述JavaScript的所有對象,都有自己的繼承鏈。也就是說,每個物件都繼承另一個對象,該物件稱為「原型」(prototype)物件。只有null除外,它沒有自己的原型物件。

原型物件的重要性在於,如果A物件是B物件的原型,那麼B物件可以拿到A物件的所有屬性和方法。 Object.getPrototypof方法用於取得目前物件的原型物件。

var p = Object.getPrototypeOf(obj);
登入後複製

上面程式碼中,物件p就是物件obj的原型物件。

Object.create方法用來產生一個新的對象,繼承指定對象。

var obj = Object.create(p);
登入後複製

上面程式碼中,新產生的obj物件的原型就是物件p。

非標準的__proto__屬性(前後各兩個底線),可以改寫某個物件的原型物件。但是,應該盡量少用這個屬性,而是用Object.getPrototypeof()和Object.setPrototypeOf(),進行原型物件的讀寫操作。

var obj = {};
var p = {};

obj.__proto__ = p;
Object.getPrototypeOf(obj) === p // true
登入後複製

上面程式碼透過__proto__屬性,將p物件設為obj物件的原型。

下面是一個實際的例子。

var a = {x: 1};
var b = {__proto__: a};
b.x // 1
登入後複製

上面程式碼中,b物件透過__proto__屬性,將自己的原型物件設為a對象,因此b物件可以拿到a物件的所有屬性和方法。 b物件本身並沒有x屬性,但是JavaScript引擎透過__proto__屬性,找到它的原型物件a,然後讀取a的x屬性。

new指令透過建構函式新建實例對象,實質就是將實例物件的原型綁定建構函式的prototype屬性,然後在實例物件上執行建構函式。

var o = new Foo();

// 等同于
var o = new Object();
o.__proto__ = Foo.prototype;
Foo.call(o);
登入後複製

原型物件自己的__proto__屬性,也可以指向其他對象,從而一級一級地形成「原型鏈」(prototype chain)。

var a = { x: 1 };
var b = { __proto__: a };
var c = { __proto__: b };

c.x // 1
登入後複製

要注意的是,一級級向上,在原型鏈尋找某個屬性,對性能是有影響的。所尋找的屬性在越上層的原型對象,對效能的影響越大。如果尋找某個不存在的屬性,將會遍歷整個原型鏈。

this的動作指向不管this在哪裡定義,使用的時候,它總是指向當前對象,而不是原型對象。

var o = {
 a: 2,
 m: function(b) {
  return this.a + 1;
 }
};

var p = Object.create(o);
p.a = 12;

p.m() // 13
登入後複製

上面程式碼中,p物件的m方法來自它的原型物件o。這時,m方法內部的this對象,不指向o,而是指向p。

建構函數的繼承這個小節介紹,如何讓一個建構函數,繼承另一個建構子。

假定有一個Shape建構子。

function Shape() {
 this.x = 0;
 this.y = 0;
}

Shape.prototype.move = function (x, y) {
 this.x += x;
 this.y += y;
 console.info('Shape moved.');
};
Rectangle构造函数继承Shape。

function Rectangle() {
 Shape.call(this); // 调用父类构造函数
}
// 另一种写法
function Rectangle() {
 this.base = Shape;
 this.base();
}

// 子类继承父类的方法
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

rect instanceof Rectangle // true
rect instanceof Shape // true

rect.move(1, 1) // 'Shape moved.'
登入後複製

上面程式碼表示,建構函式的繼承分成兩部分,一部分是子類別呼叫父類別的建構方法,另一部分是子類別的原型指向父類別的原型。

上面程式碼中,子類別是整體繼承父類別。有時,只需要單一方法的繼承,這時可以採用下面的寫法。

ClassB.prototype.print = function() {
 ClassA.prototype.print.call(this);
 // some code
}
登入後複製

上面程式碼中,子類別B的print方法先呼叫父類別A的print方法,再部署自己的程式碼。這就等於繼承了父類別A的print方法。

__proto__屬性__proto__屬性指向目前物件的原型對象,即建構函數的prototype屬性。

var obj = new Object();

obj.__proto__ === Object.prototype
// true
obj.__proto__ === obj.constructor.prototype
// true
登入後複製

上面程式碼首先新建了一個物件obj,它的__proto__屬性,指向建構函式(Object或obj.constructor)的prototype屬性。所以,兩者比較以後,回傳true。

因此,取得實例物件obj的原型對象,有三種方法。

  • obj.__proto__

  • #obj.constructor.prototype

  • Object.getPrototypeOf(obj)

上面三種方法之中,前兩種都不是很可靠。最新的ES6標準規定,__proto__屬性只有瀏覽器才需要部署,其他環境可以不部署。而obj.constructor.prototype在手動改變原型物件時,可能會失效。

var P = function () {};
var p = new P();

var C = function () {};
C.prototype = p;
var c = new C();

c.constructor.prototype === p // false
登入後複製

上面程式碼中,C建構子的原型物件被改成了p,結果c.constructor.prototype就失真了。所以,改變原型物件時,一般要同時設定constructor屬性。

C.prototype = p;
C.prototype.constructor = C;

c.constructor.prototype === p // true
登入後複製

所以,建議使用第三種Object.getPrototypeOf方法,取得原型物件。該方法的用法如下。

var o = new Object();

Object.getPrototypeOf(o) === Object.prototype
// true
登入後複製

可以使用Object.getPrototypeOf方法,檢查瀏覽器是否支援__proto__屬性,老式瀏覽器不支援這個屬性。

Object.getPrototypeOf({ __proto__: null }) === null
登入後複製

上面程式碼將一個物件的__proto__屬性設為null,然後使用Object.getPrototypeOf方法取得這個物件的原型,判斷是否等於null。如果目前環境支援__proto__屬性,兩者的比較結果應該是true。

有了__proto__屬性,就可以很方便得設定實例物件的原型了。假設有三個物件machine、vehicle和car,其中machine是vehicle的原型,vehicle又是car的原型,只要兩行程式碼就可以設定。

vehicle.__proto__ = machine;
car.__proto__ = vehicle;
登入後複製

下面是一個實例,透過__proto__屬性與constructor.prototype屬性兩種方法,分別讀取定義在原型物件上的屬性。

Array.prototype.p = 'abc';
var a = new Array();

a.__proto__.p // abc
a.constructor.prototype.p // abc
登入後複製

顯然,__proto__看起來更簡潔一些。

通过构造函数生成实例对象时,实例对象的__proto__属性自动指向构造函数的prototype对象。

var f = function (){};
var a = {};

f.prototype = a;
var o = new f();

o.__proto__ === a
// true
登入後複製

属性的继承属性分成两种。一种是对象自身的原生属性,另一种是继承自原型的继承属性。

对象的原生属性对象本身的所有属性,可以用Object.getOwnPropertyNames方法获得。

Object.getOwnPropertyNames(Date)
// ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"]
登入後複製

对象本身的属性之中,有的是可以枚举的(enumerable),有的是不可以枚举的。只获取那些可以枚举的属性,使用Object.keys方法。

Object.keys(Date) // []
hasOwnProperty()
登入後複製

hasOwnProperty方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。

Date.hasOwnProperty('length')
// true

Date.hasOwnProperty('toString')
// false
登入後複製

hasOwnProperty方法是JavaScript之中唯一一个处理对象属性时,不会遍历原型链的方法。

对象的继承属性用Object.create方法创造的对象,会继承所有原型对象的属性。

var proto = { p1: 123 };
var o = Object.create(proto);

o.p1 // 123
o.hasOwnProperty("p1") // false
登入後複製

获取所有属性判断一个对象是否具有某个属性(不管是自身的还是继承的),使用in运算符。

"length" in Date // true
"toString" in Date // true
登入後複製

获得对象的所有可枚举属性(不管是自身的还是继承的),可以使用for-in循环。

var o1 = {p1: 123};

var o2 = Object.create(o1,{
 p2: { value: "abc", enumerable: true }
});

for (p in o2) {console.info(p);}
// p2
// p1
登入後複製

为了在for...in循环中获得对象自身的属性,可以采用hasOwnProperty方法判断一下。

for ( var name in object ) {
 if ( object.hasOwnProperty(name) ) {
  /* loop code */
 }
}
登入後複製

获得对象的所有属性(不管是自身的还是继承的,以及是否可枚举),可以使用下面的函数。

function inheritedPropertyNames(obj) {
 var props = {};
 while(obj) {
  Object.getOwnPropertyNames(obj).forEach(function(p) {
   props[p] = true;
  });
  obj = Object.getPrototypeOf(obj);
 }
 return Object.getOwnPropertyNames(props);
}
登入後複製

用法如下:

inheritedPropertyNames(Date)
// ["caller", "constructor", "toString", "UTC", "call", "parse", "prototype", "__defineSetter__", "__lookupSetter__", "length", "arguments", "bind", "__lookupGetter__", "isPrototypeOf", "toLocaleString", "propertyIsEnumerable", "valueOf", "apply", "__defineGetter__", "name", "now", "hasOwnProperty"]
登入後複製

对象的拷贝如果要拷贝一个对象,需要做到下面两件事情。

确保拷贝后的对象,与原对象具有同样的prototype原型对象。
确保拷贝后的对象,与原对象具有同样的属性。
下面就是根据上面两点,编写的对象拷贝的函数。

function copyObject(orig) {
 var copy = Object.create(Object.getPrototypeOf(orig));
 copyOwnPropertiesFrom(copy, orig);
 return copy;
}

function copyOwnPropertiesFrom(target, source) {
 Object
 .getOwnPropertyNames(source)
 .forEach(function(propKey) {
  var desc = Object.getOwnPropertyDescriptor(source, propKey);
  Object.defineProperty(target, propKey, desc);
 });
 return target;
}
登入後複製

多重继承JavaScript不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能。

function M1(prop) {
 this.hello = prop;
}

function M2(prop) {
 this.world = prop;
}

function S(p1, p2) {
 this.base1 = M1;
 this.base1(p1);
 this.base2 = M2;
 this.base2(p2);
}
S.prototype = new M1();

var s = new S(111, 222);
s.hello // 111
s.world // 222
登入後複製

上面代码中,子类S同时继承了父类M1和M2。当然,从继承链来看,S只有一个父类M1,但是由于在S的实例上,同时执行M1和M2的构造函数,所以它同时继承了这两个类的方法。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

详细介绍在JS中Map和ForEach的区别

js装饰设计模式学习心得(详细解答)

详解解读JS数值Number类型(图文教程)

以上是JavaScript程式中實作繼承特性的方式(圖文教學)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1663
14
CakePHP 教程
1420
52
Laravel 教程
1315
25
PHP教程
1266
29
C# 教程
1239
24
建議:優秀JS開源人臉偵測辨識項目 建議:優秀JS開源人臉偵測辨識項目 Apr 03, 2024 am 11:55 AM

人臉偵測辨識技術已經是一個比較成熟且應用廣泛的技術。而目前最廣泛的網路應用語言非JS莫屬,在Web前端實現人臉偵測辨識相比後端的人臉辨識有優勢也有弱勢。優點包括減少網路互動、即時識別,大大縮短了使用者等待時間,提高了使用者體驗;弱勢是:受到模型大小限制,其中準確率也有限。如何在web端使用js實現人臉偵測呢?為了實現Web端人臉識別,需要熟悉相關的程式語言和技術,如JavaScript、HTML、CSS、WebRTC等。同時也需要掌握相關的電腦視覺和人工智慧技術。值得注意的是,由於Web端的計

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

股票分析必備工具:學習PHP和JS繪製蠟燭圖的步驟 股票分析必備工具:學習PHP和JS繪製蠟燭圖的步驟 Dec 17, 2023 pm 06:55 PM

股票分析必備工具:學習PHP和JS繪製蠟燭圖的步驟,需要具體程式碼範例隨著網路和科技的快速發展,股票交易已成為許多投資者的重要途徑之一。而股票分析是投資人決策的重要一環,其中蠟燭圖被廣泛應用於技術分析。學習如何使用PHP和JS繪製蠟燭圖將為投資者提供更多直觀的信息,幫助他們更好地做出決策。蠟燭圖是一種以蠟燭形狀來展示股票價格的技術圖表。它展示了股票價格的

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

PHP與JS開發技巧:掌握繪製股票蠟燭圖的方法 PHP與JS開發技巧:掌握繪製股票蠟燭圖的方法 Dec 18, 2023 pm 03:39 PM

隨著網路金融的快速發展,股票投資已經成為了越來越多人的選擇。而在股票交易中,蠟燭圖是常用的技術分析方法,它能夠顯示股票價格的變動趨勢,幫助投資人做出更精準的決策。本文將透過介紹PHP和JS的開發技巧,帶領讀者了解如何繪製股票蠟燭圖,並提供具體的程式碼範例。一、了解股票蠟燭圖在介紹如何繪製股票蠟燭圖之前,我們首先需要先了解什麼是蠟燭圖。蠟燭圖是由日本人

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

See all articles