這兩天在看vue的原始碼,發現作者定義對映字典的時候,喜歡用Object.create(null),而不是直接定義一個物件字面量,那麼兩者有什麼區別呢,又存在什麼業務場景呢
let m = Object.create(null);
let n = {};
// 猜測下,m和n有什麼區別呢
console.log(m);
console.log(n);
複製程式碼
就是一個純粹的空物件
繼承了物件原型的空物件,也就是說存在n.toString();
Object.create(proto, [propertiesObject]) 方法
- proto 新建物件的原型物件
- propertiesObject 可選,新增到新建物件的屬性(不是原型鏈的屬性),預設可列舉,引數對應Object.defineProperties的第二個引數
{} 相當於 Object.create(Object.ptototype), 現在你明白他們之間的區別了吧
for...in可以遍歷n的可列舉屬性(功能同Object.keys())
這裡要謝謝@IZumi提醒(試了一下發現沒有列印toString\get\set方法屬性,後來才發現混淆了兩個概念,就是__proto__和prototype)
修正之後如下:
function A() {
console.log('我是函式A')
};
// 定義原型物件
let protoObj = {};
protoObj = Object.defineProperty(protoObj, 'a', {
enumerable: false, // 不可列舉
value: 'a屬性'
});
protoObj.b = 'b屬性';
A.prototype = protoObj;
let a = new A();
// 這裡的let...in 和Object.keys()類似,都能訪問可列舉屬性
for (let key in a) {
console.log(key, a[key]); // b b屬性
}
複製程式碼
接下來判斷下上文截圖上提到的n.__proto__中的toString()方法是否列舉
// getOwnPropertyNames方法列印所有屬性,可列舉的和不可列舉的
let res1 = Object.getOwnPropertyNames(n.__proto__);
console.log(res1);
// 結果如下
// ["constructor", "__defineGetter__", "__defineSetter__", "hasOwnProperty", "__lookupGetter__", "__lookupSetter__", "isPrototypeOf", "propertyIsEnumerable", "toString", "valueOf", "__proto__", "toLocaleString"]
// 上文我們知道Object.keys()只能訪問可列舉屬性
let res2 = Object.keys(n.__proto__);
console.log(res2);
// []
複製程式碼
結果顯而易見,繼承Object.prototype而來的父方法,是客觀存在、可呼叫的,不可列舉、不可遍歷的
另外這個__proto__屬性, 是一個物件的隱式原型,指向構造該物件的建構函式的原型
console.log(a.__proto__ === A.prototype) // true
複製程式碼
這個以後再做深入討論。
ps. 剛開始用md語法寫文件,用的還不是很熟練,以後有更多跟有內涵的文章給大家分享,加油加油!