【问题标题】:not using `new` keyword for contructor prototype method mutates original object构造函数原型方法不使用`new`关键字改变原始对象
【发布时间】:2019-05-06 07:23:07
【问题描述】:

鉴于以下代码,我将记录 2 个 Person 原型实例

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

person = new Person('bob');
person2 = new person.constructor('tom')
console.log(person);
console.log(person2);

有趣的是,如果我们省略 new 关键字,如下例所示:

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

person = new Person('bob');
person2 = person.constructor('tom')
console.log(person);
console.log(person2);

实际上似乎构造函数被重新运行并使用新参数改变对象。这是怎么回事?

如果没有 new 关键字,则根本不会向 person2 返回任何内容。 person 的 name 属性现在是 'tom'

如果之前为真,那么没有new 关键字的构造函数会改变原始对象,是否有一个用例可以在对象上再次调用构造函数?

【问题讨论】:

  • 只是一个猜测,但也许如果您将对象用作单例并希望通过构造函数更改其中的某些值。
  • 在这种情况下为什么不直接使用实例方法
  • 就像我说的,我只是猜测,我真的没有具体的例子。也许其他人会。
  • 我想这一切都应该从“构造函数”的定义开始。然后我们讨论为什么我们要将它用于预期目的之外的用途。
  • 这就是构造函数在没有new 关键字的情况下所做的事情吗?

标签: javascript


【解决方案1】:

如果调用 ES5 构造函数时没有 new 关键字(即 调用 而不是 constructed),并且它没有 return 语句,它将返回undefined

另外,你通过dot notationperson.constructor('tom'),以person作为函数调用的this上下文调用构造函数,相当于person.constructor.call(person, 'tom'),所以它会覆盖您初始化的第一个实例。


当 ES5 是最新规范时,曾经有点常见的相关模式是通过使用 instanceof 检查来方便地避免误用构造函数,从而使用自校正构造函数。在这种情况下不会被捕获,但如果您调用 Person('tom') 而不是更常见的 new Person('tom'),则会被捕获:

function Person(name) {
  if (!(this instanceof Person)) return new Person(name);

  this.name = name;
}

console.log(new Person('bob'));
console.log(Person('tom'));

【讨论】:

  • 太棒了,有没有.constructor 没有new 关键字的用例?
  • 我几乎不会将其称为“用例”,而是将其称为“坏习惯”,但是是的,这种行为在语言规范中得到了很好的定义。
【解决方案2】:

当你不使用new 时,Person 只是一个常规函数。调用它将接受一个参数并在this 上设置name 属性。以这种方式调用的this 指的是你刚刚创建的实例。该函数不返回任何内容,因此它本质上是一个 setter。

你会偶尔看到这种构造函数的使用方式和继承模式:

function SuperClass(name) {
  this.name = name
}

function ChildClass(city, name) {
  this.city = city
  // use the superClass constructor to set properties:
  SuperClass.call(this, name)
}
// manipulate prototype 

let me = new ChildClass("Anchorage", "Mark")
console.log(me)

当您可以只创建一个专用的 setter 函数时,在其他情况下利用这一点可能会造成不必要的混乱。

【讨论】:

    【解决方案3】:

    来自 MDN 关于new 运算符:

    new 运算符创建用户定义对象类型的实例或 具有构造函数的内置对象类型之一 function.new 关键字做了以下 4 件事

    1. 它凭空创造了一个全新的对象。
    2. 它将这个对象链接到另一个对象
    3. 步骤 1 中新创建的对象作为 this 上下文传递
    4. 如果函数没有返回它自己的对象,则返回这个

    如果在不使用 new 操作符的情况下调用构造函数,则它的操作与任何其他 Object 方法一样。

    【讨论】:

    • 在这种情况下会改变对象,.constructor 是否有任何用例?
    • Andrew Kim 所说的 - 无需重复。
    猜你喜欢
    • 1970-01-01
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 2015-10-10
    相关资源
    最近更新 更多