Проверка работоспособности: `util.inherits (Child, Parent);`: вещи, связанные с прототипными свойствами Ребенка, не должны влиять на свойства родителя? [Дубликат]

Попытка объяснить это более описательно,

Операция 1:

x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]

x[0][0] = 1
print(x) # [[1, 0], [0, 0]]

Операция 2:

y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [1, 0]]

Заметил, почему не изменяется первый элемент первого списка не изменил второй элемент каждого списка? Это потому, что [0] * 2 действительно представляет собой список из двух чисел, и ссылка на 0 не может быть изменена.

Если вы хотите создать копии клонов, попробуйте выполнить операцию 3:

import copy
y = [0] * 2   
print(y)   # [0, 0]

y = [y, copy.deepcopy(y)]  
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [0, 0]]

еще один интересный способ создания копий клонов, операция 4:

import copy
y = [0] * 2
print(y) # [0, 0]

y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]

y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]
12
задан Bergi 8 June 2014 в 14:13
поделиться

3 ответа

Нет несогласованности. Просто не думайте о вложенных объектах: свойство direct объекта всегда либо на его прототипе, либо на собственном свойстве. Не имеет значения, если значение свойства является примитивным или объектом.

Итак, когда вы делаете

var parent = {
    x: {a:0}
};
var child = Object.create(parent);

child.x будет ссылаться на тот же объект, что и parent.x - тот {a:0} объект. И когда вы измените его свойство:

var prop_val = child.x; // == parent.x
prop_val.a = 1;

оба будут затронуты. Чтобы изменить «вложенное» свойство независимо, вам сначала нужно создать независимый объект:

child.x = {a:0};
child.x.a = 1;
parent.x.a; // still 0

Что вы можете сделать, это

child.x = Object.create(parent.x);
child.x.a = 1;
delete child.x.a; // (child.x).a == 0, because child.x inherits from parent.x
delete child.x; // (child).x.a == 0, because child inherits from parent

, что означает, что они не совсем независимые - но все же два разных объекта.

10
ответ дан Bergi 20 August 2018 в 16:24
поделиться
  • 1
  • 2
    "прямое свойство объекта всегда либо на его прототипе, либо на собственном свойстве" . Для меня прямое свойство означает собственное свойство объектов, а те, что в его прототипной цепочке, можно назвать непрямого . Можете ли вы объяснить, что именно вы подразумеваете под прямым свойством, или что такое косвенное свойство ..? – T J 18 November 2015 в 20:55
  • 3
    @TJ Я думаю, что использовал термин «прямой». для обозначения противоположности "вложенных" Вот. Один уровень в цепочке свойств, так сказать. – Bergi 18 November 2015 в 20:59

Я думаю, что происходит, когда вы создаете person2, его свойства sex и info относятся к ним в nestObj. Когда вы ссылаетесь на person2.info, так как person2 не переопределяет свойство info, оно переходит к прототипу и изменяет объект там.

Похоже, что это «правильный» способ сделать это способ, которым вы строите person3, чтобы объект имел свой собственный объект info для изменения и не доходил до прототипа.

Я тоже читаю книгу (медленно) , поэтому я сочувствую вам. :) [/ Д2]

1
ответ дан havanki4j 20 August 2018 в 16:24
поделиться

Я изменил примеры, чтобы лучше продемонстрировать, что здесь происходит. Демо

Сначала мы создаем объект с тремя свойствами; Число, строка и объект с одним свойством со строковым значением.

Затем мы создаем второй объект из первого, используя Object.create();

var obj1 = { 
    num : 1,
    str : 'foo',
    obj : { less: 'more' }
};
var obj2 = Object.create( obj1 );

console.log( '[1] obj1:', obj1 );
console.log( '[1] obj2:', obj2 );
"[1] obj1:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "more"
  },
  str: "foo"
}
"[1] obj2:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "more"
  },
  str: "foo"
}

Выглядит хорошо? У нас есть наш первый объект и второй скопированный объект.

Не так быстро; Давайте посмотрим, что произойдет, когда мы изменим некоторые значения для первого объекта.

obj1.num = 3;
obj1.str = 'bar';
obj1.obj.less = 'less';

console.log( '[2] obj1:', obj1 );
console.log( '[2] obj2:', obj2 );
"[2] obj1:"
[object Object] {
  num: 3,
  obj: [object Object] {
    less: "less"
  },
  str: "bar"
}
"[2] obj2:"
[object Object] {
  num: 3,
  obj: [object Object] {
    less: "less"
  },
  str: "bar"
}

Теперь снова у нас есть наш первый объект с изменениями и копия этого объекта. Что здесь происходит?

Давайте проверим, имеют ли объекты свои собственные свойства.

for( var prop in obj1 ) console.log( '[3] obj1.hasOwnProperty( ' + prop + ' ): ' + obj1.hasOwnProperty( prop ) );
for( var prop in obj2 ) console.log( '[3] obj2.hasOwnProperty( ' + prop + ' ): ' + obj2.hasOwnProperty( prop ) );
"[3] obj1.hasOwnProperty( num ): true"
"[3] obj1.hasOwnProperty( str ): true"
"[3] obj1.hasOwnProperty( obj ): true"
"[3] obj2.hasOwnProperty( num ): false"
"[3] obj2.hasOwnProperty( str ): false"
"[3] obj2.hasOwnProperty( obj ): false"

obj1 имеет все свои свойства, как мы и определили, но obj2 нет.

Что происходит, когда мы меняем некоторые свойства obj2?

obj2.num = 1;
obj2.str = 'baz';
obj2.obj.less = 'more';

console.log( '[4] obj1:', obj1 );
console.log( '[4] obj2:', obj2 );
for( var prop in obj1 ) console.log( '[4] obj1.hasOwnProperty( ' + prop + ' ): ' + obj1.hasOwnProperty( prop ) );
for( var prop in obj2 ) console.log( '[4] obj2.hasOwnProperty( ' + prop + ' ): ' + obj2.hasOwnProperty( prop ) );
"[4] obj1:"
[object Object] {
  num: 3,
  obj: [object Object] {
    less: "more"
  },
  str: "bar"
}
"[4] obj2:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "more"
  },
  str: "baz"
}
"[4] obj1.hasOwnProperty( num ): true"
"[4] obj1.hasOwnProperty( str ): true"
"[4] obj1.hasOwnProperty( obj ): true"
"[4] obj2.hasOwnProperty( num ): true"
"[4] obj2.hasOwnProperty( str ): true"
"[4] obj2.hasOwnProperty( obj ): false"

Итак, num и str изменены на obj2, а не на obj1 так, как мы этого хотели, но obj1.obj.less изменилось, когда оно не должно было быть.

Из проверок hasOwnProperty() мы можем видеть, что, хотя мы изменили obj2.obj.less, мы не " t установить obj2.obj первым. Это означает, что мы все еще ссылаемся на obj1.obj.less.

Давайте создадим объект из obj1.obj и назначим его obj2.obj и посмотрим, дает ли это нам то, что мы ищем.

obj2.obj = Object.create( obj1.obj );

console.log( '[5] obj1:', obj1 );
console.log( '[5] obj2:', obj2 );
for( var prop in obj1 ) console.log( '[5] obj1.hasOwnProperty( ' + prop + ' ): ' + obj1.hasOwnProperty( prop ) );
for( var prop in obj2 ) console.log( '[5] obj2.hasOwnProperty( ' + prop + ' ): ' + obj2.hasOwnProperty( prop ) );
"[5] obj1:"
[object Object] {
  num: 3,
  obj: [object Object] {
    less: "more"
  },
  str: "bar"
}
"[5] obj2:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "more"
  },
  str: "baz"
}
"[5] obj1.hasOwnProperty( num ): true"
"[5] obj1.hasOwnProperty( str ): true"
"[5] obj1.hasOwnProperty( obj ): true"
"[5] obj2.hasOwnProperty( num ): true"
"[5] obj2.hasOwnProperty( str ): true"
"[5] obj2.hasOwnProperty( obj ): true"

Хорошо, теперь obj2 имеет свое собственное свойство obj. Давайте посмотрим, что произойдет, когда мы изменим obj2.obj.less сейчас.

obj2.obj.less = 'less';

console.log( '[6] obj1:', obj1 );
console.log( '[6] obj2:', obj2 );
"[6] obj1:"
[object Object] {
  num: 3,
  obj: [object Object] {
    less: "more"
  },
  str: "bar"
}
"[6] obj2:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "less"
  },
  str: "baz"
}

Так что все это говорит нам, что если свойство еще не было изменено на созданном объекте, любой get запросы к созданному объекту для этого свойства будут перенаправлены на исходный объект.

Запрос set для obj2.obj.less = 'more' из предыдущего кодового блока сначала требует запроса get для obj2.obj, который не существует в obj2 в этой точке, поэтому он пересылает obj1.obj и, в свою очередь, obj1.obj.less.

Затем, наконец, когда мы снова читаем obj2, мы еще не установили obj2.obj, чтобы запрос get был перенаправлен на obj1.obj и возвратите параметр, который мы ранее изменили, в результате чего эффект изменения свойства второго объекта объекта-потомка, похоже, изменил оба параметра, но на самом деле он фактически меняет первый.


Вы можете использовать эта функция возвращает новый объект, полностью отделенный от оригинала рекурсивно.

Демо

var obj1 = { 
    num : 1,
    str : 'foo',
    obj : { less: 'more' }
};
var obj2 = separateObject( obj1 );

function separateObject( obj1 ) {

    var obj2 = Object.create( Object.getPrototypeOf( obj1 ) );
    for(var prop in obj1) {
        if( typeof obj1[prop] === "object" )
            obj2[prop] = separateObject( obj1[prop] );
        else
            obj2[prop] = obj1[prop];
    }

    return obj2;
}

console.log( '[1] obj1:', obj1 );
console.log( '[1] obj2:', obj2 );
for( var prop in obj1 ) console.log( '[1] obj1.hasOwnProperty( ' + prop + ' ): ' + obj1.hasOwnProperty( prop ) );
for( var prop in obj2 ) console.log( '[1] obj2.hasOwnProperty( ' + prop + ' ): ' + obj2.hasOwnProperty( prop ) );
"[1] obj1:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "more"
  },
  str: "foo"
}
"[1] obj2:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "more"
  },
  str: "foo"
}
"[1] obj1.hasOwnProperty( num ): true"
"[1] obj1.hasOwnProperty( str ): true"
"[1] obj1.hasOwnProperty( obj ): true"
"[1] obj2.hasOwnProperty( num ): true"
"[1] obj2.hasOwnProperty( str ): true"
"[1] obj2.hasOwnProperty( obj ): true"

Давайте посмотрим, что произойдет, когда мы изменим некоторые переменных.

obj1.num = 3;
obj1.str = 'bar';
obj1.obj.less = 'less';

console.log( '[2] obj1:', obj1 );
console.log( '[2] obj2:', obj2 );
"[2] obj1:"
[object Object] {
  num: 3,
  obj: [object Object] {
    less: "less"
  },
  str: "bar"
}
"[2] obj2:"
[object Object] {
  num: 1,
  obj: [object Object] {
    less: "more"
  },
  str: "foo"
}

Все работает точно так, как вы ожидали.

1
ответ дан Tiny Giant 20 August 2018 в 16:24
поделиться
  • 1
    Какая консоль делает такие объекты console.log, не отображая структуры наследования? – Bergi 24 August 2015 в 01:17
  • 2
    Для separateObject я рекомендую Object.create(Object.getPrototypeOf(obj1)) – Bergi 24 August 2015 в 01:18
  • 3
    Я скопировал вывод с консоли JSBin. Я просто попробовал Object.getPrototypeOf(obj1), но он возвратил пустой объект. Я что-то упускаю? я – Tiny Giant 24 August 2015 в 04:38
  • 4
    Конечно, это так, вот в чем смысл - obj1 имеет пустой прототип, и поэтому должен obj2. Вам нужно будет исправить цикл и сделать for (var prop in obj1). – Bergi 24 August 2015 в 12:54
  • 5
    Я вижу, что вы сейчас получаете. Я обновил свой ответ. – Tiny Giant 24 August 2015 в 17:54
Другие вопросы по тегам:

Похожие вопросы: