如何从仅调用另一个构造函数的函数实例化新对象?

问题描述

function Product(name,price) {
    this.name = name;
    this.price = price;
}
  
function Food(name,price) {
    Product.call(this,name,price); 
}

const item = new Food('cheese',50)

console.log(item.name)

我不明白这个。当新对象 item 不是构造函数时如何从 Food 函数实例化,但它只包含另一个函数,然后使用传递 call()this 方法调用这是指新实例化的对象? Product 函数如何成为 item 对象的构造函数?我不明白这种转移是如何发生的,因为 Food 不是构造函数,而且 Product.call() 不返回 Product 函数内容,这会使 {{1 }} 函数构造函数

有人可以向我解释一下吗?

解决方法

当您使用 new 关键字调用函数时,它会创建一个对象实例。让我们称之为this。在函数内部,我们可以为 this 赋值,因此它是 this 的属性。

每个函数本质上都可以用作构造函数,但是如果我们不给 this 赋值,它就没有任何属性。因此,在您的情况下,我们使用 Food 函数作为构造函数(在 new 关键字的帮助下),而不是手动将内容分配给函数中的 this,我们调用使用 this 作为对象的不同函数,我们希望将属性分配给。

,

乍一看,ProductFood 都像经典的构造函数。让我们看看实例化从哪里开始...... new Food 使用 Food 作为构造函数,因此,在构造/实例化时,thisFood 上下文已经引用了一个Food 实例。后者通过非实例化 Product.call 作为 thisArgs 传递到 Product 的调用/调用时间。因此,现在有一个 Food 实例被 this 处理为 Product 上下文,它确实将 nameprice 属性添加/增加到了 {{1} } 实例。

看起来像构造函数(具有 Food 上下文)但对于对象是 never instantiated but always explicitly applied either via call or apply 的东西是编写 mixin 的可能方法之一。实际上,该示例显示了 the most classic purely function-based mixin 模式之一。

更多 ... (自我推销) ...

注意 ...需要注意的是,使用类构造函数作为 mixin 只适用于纯函数。真正/真实的类(基于语法的)构造函数不能applyed/called,而只能通过new operator实例化。

下面例子的日志确实证明了上面的解释......

this
function Product(name,price) {
  this.name = name;
  this.price = price;
}

function Food(name,price) {
  Product.call(this,name,price); 
}

const item = new Food('cheese',50);

console.log({ item });

console.log(
  '(Object.getPrototypeOf(item) === Product.prototype) ?',(Object.getPrototypeOf(item) === Product.prototype)
);
console.log(
  '(Object.getPrototypeOf(item) === Food.prototype) ?',(Object.getPrototypeOf(item) === Food.prototype)
);

console.log(
  '(item instanceof Product) ?',(item instanceof Product)
);
console.log(
  '(item instanceof Food) ?',(item instanceof Food)
);
console.log(
  '(item instanceof Object) ?',(item instanceof Object)
);

编辑:

OP 的问题。

我知道 .as-console-wrapper { min-height: 100%!important; top: 0; } 中的 this 指的是新实例 Food(),但我不明白当您将 item 传递给this,现在 Product() 中的 this.name 被分配给传递的 Product()?首先,我以为this改变了对象所有者,但是call()还没有被实例化,那么它怎么会有一个新的对象所有者?

A.

不应被 Product() 的命名和大写字母混淆。需要将其视为具有 Product 上下文的普通函数,因此是一种方法,仍然“自由浮动”本身没有分配给一个对象(永远不会)。

甚至可以将其重命名为 this。使用 call / apply (显然 OP 甚至采用了前者的示例),确实在 assignProductFeatures 上下文中执行函数,该上下文必须作为方法的第一个参数传递。因此,对于给定的示例,确实将 thisname 分配给作为 price 上下文提供的任何对象/实例。

this
function assignProductFeatures(name,price) {
  // formerly known as "wan't to be" `Product` constructor.
  this.name = name;
  this.price = price;
}


const myUnknownType = {
  type: "unknown"
};
console.log({ myUnknownType });

assignProductFeatures.call(myUnknownType,'cheese',50);

console.log({ myUnknownType });


// ... deconstructing/refactoring the OP's original example code ...

// empty constructor
function Food() {}

// food factory
function createFood(name,price) {

  // create `Food` instance.
  const foodType = new Food;

  // augment the newly created type.
  assignProductFeatures.call(foodType,price);

  // return  the newly created augmented type.
  return foodType;
}

const item = createFood('cheese',50);

console.log({ item });
console.log(
  '(item instanceof assignProductFeatures) ?',(item instanceof assignProductFeatures)
);
console.log(
  '(item instanceof Food) ?',(item instanceof Object)
);

编辑:

OP 的问题。

要将 .as-console-wrapper { min-height: 100%!important; top: 0; } 中的 this.name = name 分配给 Product() 引用的传递对象,则 this 函数必须充当 {{1} } 实例,否则,Product() 中定义的属性如何被 item 中的 Product() 引用? this 使用 Food() 作为其新对象所有者调用 call(this),但 Product() 没有任何属性,并且 item 没有实例化任何对象......我无法解决这个问题!!!!我明白你对我说的话,但我无法理解机制,以及它是如何运作的!

来自你所有的问题......

item 函数必须充当项目实例的构造函数”

... 不,完全没有,因为...

Food() 应该更改对象所有者”

...完全正确,但仅在委托函数/方法的调用时间临时准确一次...

“...如果 Product() 甚至没有被实例化?”

...不需要实例化。看看上面的例子,我试图让你把 Product() 看作是一个未绑定的方法,它通过显式调用 Call()/Product 随时应用于任何对象,从而调用前者作为应用上下文中的方法。

,

您可能需要考虑以下片段:

const item = {
    name: 'cheese',price: 50,};

绝对等价于

const item = {};
item.name = 'cheese';
item.price = 50;

(除了 item 的原型)等价于

function Food() {}
const item = Object.create(Food.prototype);
item.name = 'cheese';
item.price = 50;

绝对等价于

function Food() {}
const item = new Food();
item.name = 'cheese';
item.price = 50;

绝对等价于

function Food(name,price) {
    this.name = name;
    this.price = price;
}
const item = new Food('cheese',50);

绝对等价于

function setProductProperties(obj,price) {
    obj.name = name;
    obj.price = price;
}
function Food(name,price) {
    setProductProperties(this,price); 
}
const item = new Food('cheese',50);

绝对等同于您问题中的代码

function Product(name,price) {
    this.name = name;
    this.price = price;
}  
function Food(name,price) {
    Product.call(this,50);

它们都有相同的结果 - 一个具有 item.name 属性的 .price 对象。区别仅在于它们如何实现这一点,通过函数调用具有不同的抽象级别。使用构造函数可以更轻松地实例化具有相同形状的多个对象,只需在一个地方定义该形状。