溫馨提示×

溫馨提示×

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

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

Javascript如何實現原型和原型鏈

發布時間:2022-05-06 16:06:23 來源:億速云 閱讀:240 作者:iii 欄目:大數據

這篇“Javascript如何實現原型和原型鏈”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Javascript如何實現原型和原型鏈”文章吧。

原型

Javascript中有一句話,叫一切皆是對象,當然這句話也不嚴謹,比如null和undefined就不是對象,除了這倆完全可以說Javascript一切皆是對象。而Javascript對象都有一個叫做原型的公共屬性,屬性名是_proto_。這個原型屬性是對另一個對象的引用,通過這個原型屬性我們就可以訪問另一個對象所有的屬性和方法。比如:

let numArray = [1, 2, -8, 3, -4, 7];

Array對象就有一個原型屬性指向Array.prototype,變量numArray繼承了Array.prototype對象所有的屬性和方法。

Javascript如何實現原型和原型鏈

這就是為什么可以直接調用像sort()這種方法:

console.log(numArray.sort()); // -> [-4, -8, 1, 2, 3, 7]

也就是說:

numArray.__proto__ === Array.prototype // true

對于其他對象(函數)也是一樣(比如Date(),Function(), String(),Number()等);

當一個構造函數被創建后,實例對象會繼承構造函數的原型屬性,這是構造函數的一個非常重要的特性。在Javascript中使用new關鍵字來對構造函數進行實例化??聪旅娴睦樱?/p>

const Car = function(color, model, dateManufactured) {    this.color = color;    this.model = model;    this.dateManufactured = dateManufactured;  };  Car.prototype.getColor = function() {      return this.color;  };  Car.prototype.getModel = function() {      return this.model;  };  Car.prototype.carDate = function() {      return `This ${this.model} was manufactured in the year ${this.dateManufactured}`  }  let firstCar = new Car('red', 'Ferrari', '1985');  console.log(firstCar);  console.log(firstCar.carDate());

上面的例子中,方法getColor,carDate,getModel都是對象(函數)Car的方法,而Car的實例對象firstCar可以繼承Car原型上的一切方法和屬性。

結論:每一個實例對象都有一個私有屬性_proto_,指向它的構造函數的原型對象(prototype)。

原型鏈

在Javascript中如果訪問一個對象本身不存在的屬性或是方法,就首先在它的原型對象上去尋找,如果原型對象上也不存在,就繼續在原型對象的原型對象上去尋找,直到找到為止。那么原型對象有盡頭么?所有對象的原型盡頭是Object.prototype,那么Object.prototype這個對象的_proto_指向啥呢?答案是null。我們日常開發中用到的絕大多數對象的_proto_基本不會直接指向Object.prototype,基本都是指向另一個對象。比如所有的函數的_proto_都會指向Function.prototype,所有數組的_proto_都會指向Array.prototype。

let protoRabbit = {    color: 'grey',    speak(line) {          console.log(`The ${this.type} rabbit says ${line}`);    }  };  let killerRabbit = Object.create(protoRabbit);  killerRabbit.type = "assassin";  killerRabbit.speak("SKREEEE!");

上面代碼中變量protoRabbit設置為所有兔子對象的公有屬性對象集,killerRabbit這只兔子通過Object.create方法繼承了protoRabbit的所有屬性和方法,然后給killerRabbit賦值了一個type屬性,再看下面的代碼:

let mainObject = {      bar: 2  };  // create an object linked to `anotherObject`  let myObject = Object.create( mainObject );  for (let k in myObject) {    console.log("found: " + k);  }  // found: bar  ("bar" in myObject);

如上變量myObject本身并沒有bar屬性,但這里會循著原型鏈一層一層往上找,直到找到或者原型鏈結束為止。如果到原型鏈盡頭還是沒找到該屬性,那么訪問該屬性的時候就會返回undefined了。

使用for...in關鍵字對對象進行迭代的過程,和上面訪問某個屬性循著原型鏈查找類似,會去遍歷所有原型鏈上的屬性(不論屬性是否可枚舉)。

let protoRabbit = {    color: 'grey',    speak(line) {        console.log(`The ${this.type} rabbit says ${line}`);    }  };  let killerRabbit = Object.create(protoRabbit);  killerRabbit.type = "assassin";  killerRabbit.speak("SKREEEE!");

上面的代碼中訪問speak的效率很高,但如果我們想創建很多個Rabbit對象,就必須要重復寫很多代碼。而這正是原型和構造函數的真正用武之地。

let protoRabbit = function(color, word, type) {    this.color = color;    this.word = word;    this.type = type;  };  protoRabbit.prototype.getColor = function() {      return this.color; }  protoRabbit.prototype.speak = function() {      console.log(`The ${this.type} rabbit says ${this.word}`);  }  let killerRabbit = new protoRabbit('grey', 'SKREEEEE!', 'assassin');  killerRabbit.speak();

如上代碼,使用構造函數的方式就可以節省很多的代碼。

結論:每一個實例對象都有一個私有屬性_proto_,指向它的構造函數的原型對象(prototype)。原型對象也有自己的_proto_,層層向上直到一個對象的原型對象為null。這一層層原型就是原型鏈。

創建對象的四種方法

  • 字面量對象

這是比較常用的一種方式:

let obj = {};
  • 構造函數創建

構造函數創建的方式更多用來在Javascript中實現繼承,多態,封裝等特性。

function Animal(name) {      this.name = name;  }  let cat = new Animal('Tom');
  • class創建

class關鍵字是ES6新引入的一個特性,它其實是基于原型和原型鏈實現的一個語法糖。

class Animal {    constructor(name) {      this.name = name;    }  }  let cat = new Animal('Tom');

擴展原型鏈的四種方法

  • 構造函數創建

上面例子有用到使用構造函數創建對象的例子,我們再來看一個實際的例子:

function Animal(name) {      this.name = name;  }  Animal.prototype = {      run() {      console.log('跑步');      }  }  let cat = new Animal('Tom');  cat.__proto__ === Animal.prototype; // true  Animal.prototype.__proto__ === Object.prototype; // true

優點:支持目前以及所有可想象到的瀏覽器(IE5.5都可以使用). 這種方法非???,非常符合標準,并且充分利用JIST優化。

缺點:為使用此方法,這個問題中的函數必須要被初始化。另外構造函數的初始化,可能會給生成對象帶來并不想要的方法和屬性。

  • Object.create

ECMAScript 5 中引入了一個新方法: Object.create()??梢哉{用這個方法來創建一個新對象。新對象的原型就是調用 create 方法時傳入的第一個參數:

var a = {a: 1};   // a ---> Object.prototype ---> null  var b = Object.create(a);  b.__proto__ === a; // true

優點: 支持當前所有非微軟版本或者 IE9 以上版本的瀏覽器。允許一次性地直接設置 __proto__ 屬性,以便瀏覽器能更好地優化對象。同時允許通過 Object.create(null) 來創建一個沒有原型的對象。

缺點:不支持 IE8 以下的版本;這個慢對象初始化在使用第二個參數的時候有可能成為一個性能黑洞,因為每個對象的描述符屬性都有自己的描述對象。當以對象的格式處理成百上千的對象描述的時候,可能會造成嚴重的性能問題。

  • Object.setPrototypeOf

語法:

Object.setPrototypeOf(obj, prototype)

參數:

參數名含義
obj要設置其原型的對象。
prototype該對象的新原型(一個對象 或 null).
var a = { n: 1 };  var b = { m : 2 };  Object.setPrototypeOf(a, b);  a.__proto__ === b; // true

優點:支持所有現代瀏覽器和微軟IE9+瀏覽器。允許動態操作對象的原型,甚至能強制給通過 Object.create(null) 創建出來的沒有原型的對象添加一個原型。

缺點:這個方式表現并不好,應該被棄用;動態設置原型會干擾瀏覽器對原型的優化;不支持 IE8 及以下的瀏覽器版本。

  • _proto_ 

var a = { n: 1 };  var b = { m : 2 };  a.__proto__ = b;  a.__proto__ === b; // true

使用_proto_也可以動態設置對象的原型。

優點:支持所有現代非微軟版本以及 IE11 以上版本的瀏覽器。將 __proto__ 設置為非對象的值會靜默失敗,并不會拋出錯誤。

缺點:應該完全將其拋棄因為這個行為完全不具備性能可言;干擾瀏覽器對原型的優化;不支持 IE10 及以下的瀏覽器版本。

以上就是關于“Javascript如何實現原型和原型鏈”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

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

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女