摘要:要添加到新對象的可枚舉新添加的屬性是其自身的屬性,而不是其原型鏈上的屬性的屬性。大家可能會注意到,第一個參數使用了。也就是說將設置成了新創建對象的原型,自然就不會有原型鏈上的屬性。至此,我相信大家已經對兩者的區別十分清楚了。
在Vue和Vuex的源碼中,作者都使用了Object.create(null)來初始化一個新對象。為什么不用更簡潔的{}呢?Object.create()的定義在SegmentFault和Stack Overflow等開發者社區中也有很多人展開了討論,在這里總結成文,溫故知新。
照搬一下MDN上的定義:
Object.create(proto,[propertiesObject])
proto:新創建對象的原型對象
propertiesObject:可選。要添加到新對象的可枚舉(新添加的屬性是其自身的屬性,而不是其原型鏈上的屬性)的屬性。
舉個例子(惡改了一下MDN的官方例子,看懂的點贊):
const car = { isSportsCar: false, introduction: function () { console.log(`Hi girl, this is a ${this.name}. Do you like to have a drink with me ? ${this.isSportsCar}`); } }; const porsche = Object.create(car,{ //color成為porsche的數據屬性 //顏色不喜歡,可以改色或貼膜,所以可修改 color:{ writable:true, configurable:true, value:"yellow" }, //type成為porsche的訪問器屬性 type:{ // writable、configurable等屬性,不顯式設置則默認為false // 想把普通車改成敞篷,成本有點大了,所以就設成不可配置吧 get:function(){return "convertible"}, set:function(value){"change this car to",value} } }); porsche.name = "Porsche 911"; // "name"是"porsche"的屬性, 而不是"car"的 porsche.isSportsCar = true; // 繼承的屬性可以被覆寫 porsche.introduction(); // expected output: "Hi girl, this is a Porsche 911. Do you like to have a drink with me ? true"
Object.create()的定義其實很簡單,弄清楚上面這個例子就可以了。
Object.create()、{...}的區別先看看我們經常使用的{}創建的對象是什么樣子的:
var o = {a:1}; console.log(o)
在chrome控制臺打印如下:
從上圖可以看到,新創建的對象繼承了Object自身的方法,如hasOwnProperty、toString等,在新對象上可以直接使用。
再看看使用Object.create()創建對象:
var o = Object.create(null,{ a:{ writable:true, configurable:true, value:"1" } }) console.log(o)
在chrome控制臺打印如下:
可以看到,新創建的對象除了自身屬性a之外,原型鏈上沒有任何屬性,也就是沒有繼承Object的任何東西,此時如果我們調用o.toString()會報Uncaught TypeError的錯誤。
大家可能會注意到,第一個參數使用了null。也就是說將null設置成了新創建對象的原型,自然就不會有原型鏈上的屬性。我們再把上面的例子改一改:
var o = Object.create({},{ a:{ writable:true, configurable:true, value:"1" } }) console.log(o)
將null改為{},結果是怎樣的?在chrome控制臺打印如下:
我們看到,這樣創建的對象和使用{}創建對象已經很相近了,但是還是有一點區別:多了一層proto嵌套。
我們最后再來改一下:
var o = Object.create(Object.prototype,{ a:{ writable:true, configurable:true, value:"1" } }) console.log(o)
chrome控制臺打印如下:
這次就和使用{}創建的對象一模一樣了。至此,我相信大家已經對兩者的區別十分清楚了。
Object.create(null)的使用場景再回到文章開頭的問題,為什么很多源碼作者會使用Object.create(null)來初始化一個新對象呢?這是作者的習慣,還是一個最佳實踐?
其實都不是,這并不是作者不經思考隨便用的,也不是javascript編程中的最佳實踐,而是需要因地制宜,具體問題具體分析。
我們進一步比較一下Object.create(null)和{}創建控對象的區別:
在chrome打印如下:
從上圖可以看到,使用create創建的對象,沒有任何屬性,顯示No properties,我們可以把它當作一個非常純凈的map來使用,我們可以自己定義hasOwnProperty、toString方法,不管是有意還是不小心,我們完全不必擔心會將原型鏈上的同名方法覆蓋掉。舉個例子:
//Demo1: var a= {...省略很多屬性和方法...}; //如果想要檢查a是否存在一個名為toString的屬性,你必須像下面這樣進行檢查: if(Object.prototype.hasOwnProperty.call(a,"toString")){ ... } //為什么不能直接用a.hasOwnProperty("toString")?因為你可能給a添加了一個自定義的hasOwnProperty //你無法使用下面這種方式來進行判斷,因為原型上的toString方法是存在的: if(a.toString){} //Demo2: var a=Object.create(null) //你可以直接使用下面這種方式判斷,因為存在的屬性,都將定義在a上面,除非手動指定原型: if(a.toString){}
另一個使用create(null)的理由是,在我們使用for..in循環的時候會遍歷對象原型鏈上的屬性,使用create(null)就不必再對屬性進行檢查了,當然,我們也可以直接使用Object.keys[]。
總結一下:
你需要一個非常干凈且高度可定制的對象當作數據字典的時候;
想節省hasOwnProperty帶來的一丟丟性能損失并且可以偷懶少些一點代碼的時候
用Object.create(null)吧!
其他時候,請用{}。
以上
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94135.html
摘要:使用操作符,創建一個對象,并且執行構造函數方法。使用可以返回一個字典型對象對象原型每一個對象都有一個內置的屬性指向構造它的函數屬性而構造函數的則指向構造函數本生。 對象概念 在 javascript 中, 一切引用類型均為對象。 如 function Foo () {} 中,Foo本身就是一個對象的引用。 創建對象方式 字面量方式 new 構造函數 函數聲明 Object.creat...
摘要:原文地址詳解的類博主博客地址的個人博客從當初的一個彈窗語言,一步步發展成為現在前后端通吃的龐然大物。那么,的類又該怎么定義呢在面向對象編程中,類是對象的模板,定義了同一組對象又稱實例共有的屬性和方法。這個等同于的屬性現已棄用。。 前言 生活有度,人生添壽。 原文地址:詳解javascript的類 博主博客地址:Damonare的個人博客 ??Javascript從當初的一個彈窗語言,一...
摘要:原文地址詳解的類博主博客地址的個人博客從當初的一個彈窗語言,一步步發展成為現在前后端通吃的龐然大物。那么,的類又該怎么定義呢在面向對象編程中,類是對象的模板,定義了同一組對象又稱實例共有的屬性和方法。這個等同于的屬性現已棄用。。 前言 生活有度,人生添壽。 原文地址:詳解javascript的類 博主博客地址:Damonare的個人博客 ??Javascript從當初的一個彈窗語言,一...
介紹 在創建對象的時候,我們有2種常用方法 一個是文本標記法(var obj = {}),一種是運用Object函數進行對象的創建(new Object()). 但是這兩種方式并不是創建的一個完完全全干干凈凈的對象,這里的干凈只得是沒有繼承鏈. 幸運的是,ES5為我們提供了一種創建完全干凈的對象的方法,Object.create函數,接下我將向大家介紹Obje...
閱讀 2386·2021-09-22 16:01
閱讀 3154·2021-09-22 15:41
閱讀 1171·2021-08-30 09:48
閱讀 490·2019-08-30 15:52
閱讀 3324·2019-08-30 13:57
閱讀 1713·2019-08-30 13:55
閱讀 3649·2019-08-30 11:25
閱讀 757·2019-08-29 17:25