日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

《你不知道的JavaScript》整理(四)——原型

發布時間:2025/7/14 javascript 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《你不知道的JavaScript》整理(四)——原型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、[[Prototype]]

JavaScript中的對象有一個特殊的[[Prototype]]內置屬性,其實就是對于其他對象的引用。

var myObject = {a: 2 }; myObject.a; // 2

當你試圖引用對象的屬性時會觸發原型[[Get]]操作,比如myObject.a。

1. 第一步是檢查對象本身是否有這個屬性,如果有的話就使用它。

2. 如果a不在myObject中,就需要使用對象的[[Prototype]]鏈了。

?

1)Object.prototype

普通的[[Prototype]]鏈最終都會指向內置的Object.prototype。

?

2)屬性設置和屏蔽

myObject.foo = "bar";

如 果 屬 性 名foo既 出 現 在myObject中 也 出 現 在myObject的[[Prototype]]鏈 上 層, 那么就會發生屏蔽

myObject中包含的foo屬性會屏蔽原型鏈上層的所有foo屬性,因為myObject.foo總是會選擇原型鏈中最底層的foo屬性。

有些情況下會隱式產生屏蔽:

var anotherObject = {a: 2 };var myObject = Object.create(anotherObject);anotherObject.a; // 2 myObject.a; // 2 anotherObject.hasOwnProperty("a"); // true myObject.hasOwnProperty("a"); // false myObject.a++; // 隱式屏蔽! anotherObject.a; // 2 myObject.a; // 3 myObject.hasOwnProperty("a"); // true

++操作相當于myObject.a = myObject.a + 1。

因此++操作首先會通過[[Prototype]]查找屬性a并從anotherObject.a獲取當前屬性值2,然后給這個值加1,接著用[[Put]]將值3賦給myObject中新建的屏蔽屬性a。

?

二、“類”

JavaScript中只有對象

在JavaScript中,類無法描述對象的行,(因為根本就不存在類!)對象直接定義自己的行為。

1)“類”函數

function Foo() {// ... } var a = new Foo(); console.log(Object.getPrototypeOf(a) === Foo.prototype); // true

a這個對象是在調用new Foo()時創建的,最后會被關聯到這個“Foo.prototype”對象上。

在JavaScript中不能創建一個類的多個實例,只能創建多個對象,它們[[Prototype]]關聯的是同一個對象。

從視覺角度來說,[[Prototype]]機制如下圖所示,箭頭從右到左,從下到上:

這個機制通常被稱為原型繼承,它常常被視為動態語言版本的類繼承。

?

2)“構造函數

function Foo() {// ... } var a = new Foo();

之所以認為Foo是一個“類”:

1. 其中一個原因是我們看到了關鍵字new,在面向類的語言中構造類實例時也會用到它。

2. 另一個原因是,看起來我們執行了類的構造函數方法,Foo()的調用方式很像初始化類時類構造函數的調用方式

在JavaScript中對于“構造函數”最準確的解釋是,所有帶new的函數調用

函數不是構造函數,但是當且僅當使用new時,函數調用會變成“構造函數調用”。

?

三、(原型)繼承

function Foo(name) {this.name = name; } Foo.prototype.myName = function() {return this.name; };function Bar(name, label) {Foo.call(this, name);this.label = label; } // 我們創建了一個新的 Bar.prototype 對象并關聯到 Foo.prototype Bar.prototype = Object.create(Foo.prototype); // 注意!現在沒有 Bar.prototype.constructor 了 // 如果你需要這個屬性的話可能需要手動修復一下它 Bar.prototype.myLabel = function() {return this.label; };var a = new Bar("a", "obj a"); a.myName(); // "a" a.myLabel(); // "obj a"

原型繼承的機制,是指a可以“繼承”Foo.prototype并訪問Foo.prototype的myName()函數。

面這兩種方式是常見的錯誤做法

// 和你想要的機制不一樣! Bar.prototype = Foo.prototype;// 基本上滿足你的需求,但是可能會產生一些副作用 :( Bar.prototype = new Foo();

1.?第一種只是讓Bar.prototype直接引用Foo.prototype對象。因此當你執行類似Bar.prototype.myLabel = ...的賦值語句時會直接修改Foo.prototype對象本身

2.?第二種的確會創建一個關聯到Bar.prototype的新對象。但是它使用了Foo(..)的“構造函數調用”,如果函數Foo有一些副作用(比如寫日志、修改狀態、注冊到其他對象、給this添加數據屬性,等等)的話,就會影響到Bar()的“后代”

兩種正確的把Bar.prototype關聯到Foo.prototype的方法:

// ES6 之前需要拋棄默認的 Bar.prototype Bar.ptototype = Object.create( Foo.prototype );// ES6 開始可以直接修改現有的 Bar.prototype Object.setPrototypeOf( Bar.prototype, Foo.prototype );

?

1)檢查“類”關系

在傳統的面向類環境中,檢查一個實例(JavaScript中的對象)的繼承祖先(JavaScript中的委托關聯)通常被稱為內省(或者反射)。

function Foo() { // ... } Foo.prototype.blah = ...; var a = new Foo();

如何通過內省找出a的“祖先”(委托關聯)呢?

1.?第一種站在“類”的角度來判斷:

a instanceof Foo; // true

instanceof回答的問題是:在a的整條[[Prototype]]鏈中是否有指向Foo.prototype的對象?

這個方法只能處理對象(a)和函數(帶.prototype引用的Foo)之間的關系。

?

2.?第二種判斷[[Prototype]]反射的方法,它更加簡潔:

Foo.prototype.isPrototypeOf( a ); // true

isPrototypeOf回答的問題是:在a的整條[[Prototype]]鏈中是否出現過Foo.prototype?

同樣的問題,同樣的答案,但是在第二種方法中并不需要間接引用函數(Foo),它的.prototype屬性會被自動訪問。

我們只需要兩個對象就可以判斷它們之間的關系。舉例來說:

// 非常簡單:b 是否出現在 c 的 [[Prototype]] 鏈中? b.isPrototypeOf( c );

?

2)獲取一個對象的[[Prototype]]鏈

1. 在ES5中,標準的方法是:

Object.getPrototypeOf( a );console.log(Object.getPrototypeOf( a ) === Foo.prototype); // true

2. 瀏覽器也支持一種非標準的方法來訪問內部[[Prototype]]屬性:

a.__proto__ === Foo.prototype; // true

.__proto__的實現大致上是這樣的:

Object.defineProperty(Object.prototype, "__proto__", {get: function() {return Object.getPrototypeOf(this);},set: function(o) {// ES6 中的 setPrototypeOf(..)Object.setPrototypeOf(this, o);return o;} });

訪問(獲取值)a.__proto__時,實際上是調用了a.__proto__()(調用getter函數)。

雖然getter函數存在于Object.prototype對象中,但是它的this指向對象a,所以和Object.getPrototypeOf( a )結果相同

?

四、對象關聯

[[Prototype]]機制就是存在于對象中的一個內部鏈接,它會引用其他對象

這個鏈接的作用是:如果在對象上沒有找到需要的屬性或者方法引用,引擎就會繼續在[[Prototype]]關聯的對象上進行查找。

這一系列對象的鏈接被稱為“原型鏈”。

var foo = {something: function() {console.log("Tell me something good...");} }; var bar = Object.create(foo); bar.something(); // Tell me something good...

我們并不需要類來創建兩個對象之間的關系,只需要通過委托來關聯對象就足夠了。

Object.create()的polyfill代碼:

Object.create = function(o) {function F() {}F.prototype = o;return new F(); };

使用了一個一次性函數F,我們通過改寫它的.prototype屬性使其指向想要關聯的對象,然后再使用new F()來構造一個新對象進行關聯。

?

總結

以上是生活随笔為你收集整理的《你不知道的JavaScript》整理(四)——原型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。