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

歡迎訪問 生活随笔!

生活随笔

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

javascript

你不知道的JS5-原型

發布時間:2023/12/2 javascript 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 你不知道的JS5-原型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、原型

[[prototype]]

js中的對象有一個特殊的[[prototype]]內置屬性,其實就是對于其他對象的引用,幾乎所有的對象在創建時[[prototype]]屬性都會被賦予一個非空的值

使用for..in和in操作符都會查找對象的整條原型鏈

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

2、屬性設置與屏蔽

myobject.foo = "bar"

1)如果myobject對象中包含名為foo的普通數據訪問屬性,這條賦值語句只會修改已有的屬性值

2)如果foo不是直接存在于myobject中,[[prototype]]鏈就會發生遍歷,類似[[get]]操作,如果原型鏈上找不到foo,foo就會直接添加到myobject上

3)如果屬性名foo又存在于myobject又出現在[[prototype]]鏈上層,那么就會發生屏蔽。myobject中包含的foo屬性會屏蔽原型鏈上層的所有foo屬性,因為myobject.foo總是會選擇原型鏈中最底層的foo屬性

分析一下foo不直接存在于myobject而是存在于原型鏈上層時myobject.foo = 'bar'會出現三種情況

1、如果在[[prototype]]上層存在名為foo的普通數據訪問屬性,并且沒有被標記為只讀(writable:false)那就會直接在myobject中添加一個名為foo的新屬性它是屏蔽屬性

2、如果在[[prototype]]上層存在foo但是被標記為只讀,那么無法修改已有屬性或者在myobject上創建屏蔽屬性,如果運行在嚴格模式下代碼會拋出一個錯誤

?

3、如果在[[prototype]]鏈上層存在foo并且它是一個setter那就一定會調用這個setter,foo不會被添加到mtobject

如果你希望第二種、第三種情況也能屏蔽foo就不能使用=操作符來賦值,而是使用Object.defineProperty(...)來向myobject添加foo

3、“類”函數

所有函數都會擁有一個公用并且不可枚舉的屬性,會指向另一個對象

?

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

調用Foo()時會創建a,其中一步就是將a內部的[[prototype]]鏈接到Foo.prototype所指向的對象

new Foo()會生成一個新對象(我們稱為a)這個新對象的內部鏈接[[prototype]]關聯的是Foo.prototype對象

new Foo()只是間接完成了我們的目標:一個關聯到其他對象的新對象

更直接的方法就是Object.create()

4、關于名稱

繼承意味著復制操作,js并不會復制對象的屬性,相反js會在兩個對象之間創建一個關聯,這樣一個對象就可以通過委托訪問另一個對象的屬性和函數

5、”構造函數“

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

實際上a本身并沒有.constructor屬性。

實際上.constructor引用同樣被委托給了Foo.prototype

而Foo.prototype.constructor 默認指向Foo

Foo.prototype的constructor屬性只是Foo函數在聲明時的默認屬性,如果你創建了一個對象并替換了函數默認的prototype對象引用,那么新對象并不會自動獲得.constructor屬性

修復.constructor需要很多手動操作,方法:記住:constructor并不代表被構造

?

6、構造函數還是調用

實際上Foo函數本身并不是構造函數,然而當你在普通的函數調用前面加上new關鍵字調用后,就會把這個函數調用變成構造函數調用。

實際上new會劫持所有普通函數并用構造函數的形式來調用它

function nothing(){console.log('aaa'); } var a = new nothing();//"aaa" a;//{}

nothing只是一個普通的函數,但是使用new調用時,它就會構造一個對象并賦給a,這看起來像是new的一個副作用

js中對于構造函數最準確地解釋是,所有帶new的函數調用

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

?

7、(原型)繼承

原型風格代碼:

?

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.prrototype.myLabel = function() {return this.label; } var a = new Bar("a","obj a") a.myName(); a.myLabel()

?這段代碼核心

Bar.prototype = Object.create(Foo.prototype);

調用Object.create()會憑空創建一個“新”對象并把新對象內部的[[Prototype]]關聯到指定的對象

換句話說意思是:“創建一個新的Bar.prototype對象并把它關聯到Foo.prototype”

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

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

Bar.prototype = Foo.prototype;并不會創建一個關聯到Bar.prototype的新對象,只是會讓Bar.prototype直接引用Foo.prototype,當執行Bar.prrototype.myLabel的賦值語句時會直接修改Foo.prototype本身

修改對象的[[prototype]]關聯方法:

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

?Object.create(。。。)需要創建一個新對象然后把舊對象拋棄掉,不能直接修改已有的默認對象

如果忽略掉Object.create()方法帶來的輕微性能損失(拋棄的對象需要進行垃圾回收)

?8、檢查類關系

假設有對象a,如何尋找對象a委托的對象(如果存在的話)

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

?

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

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

方法一:站在類的角度判斷

a intanceof Foo;//true

intanceof操作符的左操作數是一個普通的對象,右操作數是一個函數。

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

可是這個方法只能處理對象(a)和函數(帶.prototype引用的Foo)如果你想判斷兩個對象之間是否通過[[Prototype]]鏈關聯,只用instanceof無法實現

方法二:判斷[[Prototype]]反射的方法:

Foo.prototype.isPrototypeOf(a);//true isPrototypeOf(...)回答的問題是:在a的整條[[Prototype]]鏈中是否出現過Foo.prototype // 非常簡單:b是否出現在c的[[Prototype]]鏈中 b.isPrototypeOf(c)

?直接獲取一個對象的[[Prototype]]鏈

ES5中:

Object.getPropertyOf(a)

可以驗證一下,這個對象引用是否和我們想的一樣

Object.getPropertyOf(a) === Foo.prototype;//true

?絕大多數(不是所有!)瀏覽器也支持一種非標準的方法來訪問內部[[Prototype]]屬性

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

這個奇怪的__proto__屬性“神奇的”引用了內部的[[Prototype]]對象,如果你想直接查找(甚至可以通過.__proto__.__proto__...來遍歷)原型鏈的話,這個方法非常有用

9、對象關聯

1)創建關聯

var foo = {something: function() {console.log('tell me something good');} }; var bar = Object.create(foo); bar.something();//tell me something good Object.create()會創建一個新對象(bar)并且把它關聯到我們制定的對象foo,這樣可以充分發揮[[prototype]]機制的威力(委托)而且避免不必要的麻煩
2)內部委托比直接委托可以可以讓API接口設計更加清晰
直接委托:
var anotherObject = {cool:function() {console.log("cool");} } var myObject = Object.create(anotherObject); myObject.cool();

內部委托:

var anotherObject = {cool:function() {console.log("cool");} } var myObject = Object.create(anotherObject); myObject.docool = function(){this.cool();//內部委托 } myObject.docool()//'cool'

?如果訪問對象中并不存在的一個屬性,[[Get]]操作就會查找對象內部[[Prototype]]關聯的對象。這個關聯關系實際上定義了一條原型鏈(有點像嵌套的作用域鏈),在查找屬性時會對他進行遍歷

?雖然這些js機制和傳統的面向類語言中的“類初始化”,“類繼承”很相似,但是js中的機制有一個核心區別,就是不會復制,對象之間是通過內部的[[Prototype]]鏈關聯的
對象之間的關系不是復制而是委托。

轉載于:https://www.cnblogs.com/lu-yangstudent/p/8042019.html

總結

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

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