javascript中的Object.create:为什么我的代码输出对象而不是名称字符串值

javascript中的Object.create:为什么我的代码输出对象而不是名称字符串值,javascript,node.js,Javascript,Node.js,我测试了这个代码段并使用node.js执行 function Person(name) { this.name = name; } john = Object.create(Person); john.name = 'John'; console.log(john.name); 它返回一个人。为什么它不返回“John” 更新:我的问题不是new vs create,我完全知道new和create应该如何使用。我的问题是为什么不能像往常一样设置name属性值 它返回Person。为什么它

我测试了这个代码段并使用node.js执行

function Person(name) {
  this.name = name;
}


john = Object.create(Person);
john.name = 'John';
console.log(john.name);
它返回一个人。为什么它不返回“John”

更新:我的问题不是new vs create,我完全知道new和create应该如何使用。我的问题是为什么不能像往常一样设置name属性值

它返回
Person
。为什么它不返回“John”

因为
Object.create
行创建了一个以
Person
函数为原型的对象,
Person
函数对象对
name
属性有一个令人惊讶的定义,它阻止了对它的写入。(一旦你了解了这个定义,它就有了意义,但一开始它令人惊讶。)

当你这样做的时候,你在创造什么

john = Object.create(Person);
…是一个使用
Person
函数作为其底层原型的对象。这不会创建一个
Person
实例(将使用
Person.prototype
作为其原型),而是创建一个实际使用函数对象
Person
本身作为原型的对象

Person
函数有一个名为
name
的不可写属性,该属性是函数的名称(该名称尚未在标准中,但将在ES6中定义[目前在§9.2.11中定义],V8已经定义了)。因为该属性不可写,
john.name='john'
不做任何事情。(有关不可写属性的详细信息,请参见下文。)

如果您的目标是使用
Person.prototype
作为对象的基础原型创建一个新对象,那么您应该执行以下操作:

john = new Person();

既然
Person
接受了一个论点,你可能会接受

john = new Person('John');
…而不是随后分配给
名称


关于不可写属性的更多信息:如果您还没有遇到它们,那么不久前它们被定义为第5版规范的一部分。下面是一个例子:

var parent = {};
Object.defineProperty(parent, "foo", {
    writable: false,
    value: "original"
});
父对象具有不可写属性,
foo

console.log(parent.foo); // "original"
parent.foo = "bar";
console.log(parent.foo); // "original"
如果我们使用
parent
作为原型,即使在子对象上也无法写入
foo

var child = Object.create(parent);
console.log(child.foo); // "original"
child.foo = "bar";
console.log(child.foo); // "original"
这就是代码中发生的事情<代码>父项
子项
约翰

为了解决这个问题:如果我们想在此时在子对象上创建一个可写属性,我们可以,但不能通过赋值,我们必须使用
defineProperty

Object.defineProperty(child, "foo", {
    writable: true,
    value: child.foo    // (just sets the initial value)
});
console.log(child.foo); // "original"
child.foo = "bar";
console.log(child.foo); // "bar"
现在
child
有了自己的属性,名为
foo
,它隐藏了原型的
foo
,并且是可写的

它返回
Person
。为什么它不返回“John”

因为
Object.create
行创建了一个以
Person
函数为原型的对象,
Person
函数对象对
name
属性有一个令人惊讶的定义,它阻止了对它的写入。(一旦你了解了这个定义,它就有了意义,但一开始它令人惊讶。)

当你这样做的时候,你在创造什么

john = Object.create(Person);
…是一个使用
Person
函数作为其底层原型的对象。这不会创建一个
Person
实例(将使用
Person.prototype
作为其原型),而是创建一个实际使用函数对象
Person
本身作为原型的对象

Person
函数有一个名为
name
的不可写属性,该属性是函数的名称(该名称尚未在标准中,但将在ES6中定义[目前在§9.2.11中定义],V8已经定义了)。因为该属性不可写,
john.name='john'
不做任何事情。(有关不可写属性的详细信息,请参见下文。)

如果您的目标是使用
Person.prototype
作为对象的基础原型创建一个新对象,那么您应该执行以下操作:

john = new Person();

既然
Person
接受了一个论点,你可能会接受

john = new Person('John');
…而不是随后分配给
名称


关于不可写属性的更多信息:如果您还没有遇到它们,那么不久前它们被定义为第5版规范的一部分。下面是一个例子:

var parent = {};
Object.defineProperty(parent, "foo", {
    writable: false,
    value: "original"
});
父对象具有不可写属性,
foo

console.log(parent.foo); // "original"
parent.foo = "bar";
console.log(parent.foo); // "original"
如果我们使用
parent
作为原型,即使在子对象上也无法写入
foo

var child = Object.create(parent);
console.log(child.foo); // "original"
child.foo = "bar";
console.log(child.foo); // "original"
这就是代码中发生的事情<代码>父项
子项
约翰

为了解决这个问题:如果我们想在此时在子对象上创建一个可写属性,我们可以,但不能通过赋值,我们必须使用
defineProperty

Object.defineProperty(child, "foo", {
    writable: true,
    value: child.foo    // (just sets the initial value)
});
console.log(child.foo); // "original"
child.foo = "bar";
console.log(child.foo); // "bar"

现在
child
有了自己的名为
foo
的属性,它隐藏了原型的
foo
,并且是可写的。

FYI如果您替换
john=Object.create(Person)
john=新人
您将获得预期结果。可能重复非常非常有趣的问题。@我知道new,我的问题不是new vs create,这就是为什么我不能像往常一样重载name属性。如果替换
john=Object.create(Person),仅供参考
john=新人您将得到预期的结果。非常非常有趣的问题可能重复。@我知道new,我的问题不是new vs create,这就是为什么我不能像往常一样重载name属性。答案很好,不知道不可写属性的存在。我仍然感到惊讶,因为我认为如果它不可写,那么在尝试写它时应该会抛出一些错误。@user310291:谢谢!是的,我可能应该提到这一点。在松散模式下,这类事情通常不会抛出错误。在严格模式下,通常是这样。事实上,在严格模式下写入不可写属性通常会抛出一个er