Подробно объясните Object.create(null)

внешний интерфейс Chrome Vue.js Vuex


В исходном коде Vue и Vuex автор используетObject.create(null)для инициализации нового объекта. Почему бы не использовать более краткий{}Шерстяная ткань?

существуетSegmentFaultиStack OverflowВ сообществе разработчиков также есть много людей, которые обсуждали это здесь, резюмировали здесь, рассматривали старое и изучали новое.

Определение Object.create()

Скопируйте определение на MDN:

Object.create(proto,[propertiesObject])
  • proto: объект-прототип вновь созданного объекта
  • свойстваОбъект: Необязательно. добавить к новому объектуисчисляемый(Вновь добавленное свойство является собственным свойством, а не свойством в цепочке прототипов).

Например (я изменил официальный пример 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)и{}Отличие создания объекта управления:

Печатайте в хроме следующим образом:


Как видно из приведенного выше рисунка, при использованииcreateСозданный объект без каких-либо свойств показываетNo properties, мы можем рассматривать его как оченьчистыйКарта для использования, мы можем определить нашу собственную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[].

Суммировать:

  1. Когда вам нужен очень чистый и настраиваемый объект в качестве словаря данных;
  2. хочу сохранитьhasOwnPropertyКогда вы приносите небольшую потерю производительности и можете полениться с небольшим количеством кода

использоватьObject.create(null)Бар! В других случаях используйте{}.

выше