Как создать прототип на экземпляре объекта, который не является объектом или функцией? - PullRequest
1 голос
/ 22 мая 2019

Расширение класса Object не рекомендуется, поэтому я пытаюсь расширить объект, например:

var obj = {'a': 1, 'b': 2, 'c': 3};

Здесь литерал объекта {'a': 1, 'b': 2, 'c': 3}
такой же, как new Object({'a': 1, 'b': 2, 'c': 3}).

Я попытался obj.prototype = {d: 4}, но в качестве свойства было установлено 'prototype', а не настоящий прототип .
Забыл Object.defineProperties!
Также попыталсяObject.create: Почему это не работает?...

var ext = Object.create(obj, {'d': { value:4 }});
console.log(obj.isPrototypeOf(ext)) // => true! obj is prototype of ext
console.log(ext); // => {d: 4}
console.log(obj); // => {a: 1, b: 2, c: 3}

Console.log говорит obj.isPrototypeOf(ext) == true так почему ext не {'a': 1, 'b': 2, 'c': 3, 'd': 4}?

Как создать прототип на экземпляре объекта, который не является классом Objectили функция?

Обновление : Как Николас Тауэр ответить, я пропустил перечислимый второй параметр , который должен быть: {'d': { value:4, enumerable: true }}

У меня возникла проблема с раскрывающимся списком стрелок в консоли Chrome, по которой я пропустил щелчок, чтобы увидеть унаследованные значения.Я мог бы использовать assign() для «расширения» obj .Теперь он показывает obj = {'a': 1, 'b': 2, 'c': 3} __proto__ {d: 4}, это нормально.С точки зрения ОО это означает, что obj расширяет {d: 4}*.Сделан прототип на объекте obj.

Я принял ответ от t.888 , который помог мне увидеть, как console.log показывает объекты и правильный способ расширения существующего объекта.

Ответы [ 2 ]

3 голосов
/ 22 мая 2019

почему ext не {'a': 1, 'b': 2, 'c': 3, 'd': 4}?

Да, но выне сделал это d перечисляемым, поэтому console.log его не видит.

const obj = {'a': 1, 'b': 2, 'c': 3};
const ext = Object.create(obj, {'d': { 
  value:4, 
  enumerable: true // <---- added this
}});
console.log('ext', ext);
for (const key in ext) {
  if (ext.hasOwnProperty(key)) {
    console.log('own property', key, ext[key]);
  } else {
    console.log('inherited property', key, ext[key]);
  }
}
1 голос
/ 22 мая 2019

Вы можете использовать __proto__ для установки прототипа, но он считается устаревшей функцией:

const obj = {a: 1, b: 2, __proto__: { c: 3 }}
console.log(obj.c) // 3

Лучший способ - расширить существующий объект с помощью Object.create. Удобно определить функцию для этого:

/**
 * Extend an object by creating a new object with the given prototype.
 */
function extend(proto, obj) {
  // Create a new object with the given prototype
  const sub = Object.create(proto)

  if (obj) {
    // Copy the properties from 'obj' to the new object.
    Object.assign(sub, obj)
  }

  // Return the new object.
  return sub
}
// Define an object to serve as a prototype.
const proto = { a: 1, b: 2 }

// Create a new object with the given prototype.
const extended = extend(proto, { c: 3 })

console.log(extended.a, extended.b, extended.c) // 1 2 3

Однако, как указал другой ответ, на самом деле свойства прототипа не будут отображаться. на объект:

console.log(extended) // { c: 3 }

Хотя он там, просто не на самом объекте, а на его прототипе:

for (let key in extended) {
  console.log(key, extended[key])
}

Выход:

c 3
a 1
b 2
console.log(extended.__proto__) // { a: 1, b: 2 }

Object.assign

Если вы просто хотите скопировать и / или объединить объекты, используйте Object.assign:

const first = {a: 1}
const second = {b: 2}

// Put the properties from 'second' onto 'first'.
Object.assign(first, second) // first: {a: 1, b: 2}

// Copy 'first' and 'second' to a new object.
const third = Object.assign({c: 3}, first, second) // third: {c: 3, a: 1, b: 2}

Это примерно эквивалентно копированию свойств вручную:

const first = {a: 1}
const second = {b: 2}

for (let key in second) {
  if (second.hasOwnProperty(key)) {
    first[key] = second[key]
  }
}

console.log(first) // {a: 1, b: 2}

Обобщая этот код, мы можем создать аппроксимацию Object.assign, которая работает в старых браузерах , где Object.assign может отсутствовать:

/**
 * Assign properties from object arguments [1..n] to the
 * zeroth object argument.
 */
function assign() {
  var first, rest

  // Check of Object.assign exists and use a fallback if it doesn't.
  if (typeof Object.assign === 'function') {
    // Copy each object's properties to the first one.
    return Object.assign.apply(null, arguments)
  } else {
    first = arguments[0]
    rest = Array.prototype.slice.call(arguments, 1)
    // Copy each object's properties to the first one.
    rest.forEach((obj) => {
      for (var key in obj) {
        // Don't copy any of obj's prototype's properties.
        if (obj.hasOwnProperty(key)) {
          first[key] = obj[key]
        }
      }
    })
    return first
  }
}
const obj = assign({c: 3}, {a: 1}, {b: 2})
console.log(obj) // {c: 3, a: 1, b: 2}
...