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 }} 函数构造函数。
有人可以向我解释一下吗?
答案 0 :(得分:1)
当您使用 new
关键字调用函数时,它会创建一个对象实例。让我们称之为this
。在函数内部,我们可以为 this
赋值,因此它是 this
的属性。
每个函数本质上都可以用作构造函数,但是如果我们不给 this
赋值,它就没有任何属性。因此,在您的情况下,我们使用 Food
函数作为构造函数(在 new
关键字的帮助下),而不是手动将内容分配给函数中的 this
,我们调用使用 this
作为对象的不同函数,我们希望将属性分配给。
答案 1 :(得分:1)
乍一看,Product
和 Food
都像经典的构造函数。让我们看看实例化从哪里开始...... new Food
使用 Food
作为构造函数,因此,在构造/实例化时,this
的 Food
上下文已经引用了一个Food
实例。后者通过非实例化 Product.call
作为 thisArgs
传递到 Product
的调用/调用时间。因此,现在有一个 Food
实例被 this
处理为 Product
上下文,它确实将 name
和 price
属性添加/增加到了 {{1} } 实例。
看起来像构造函数(具有 Food
上下文)但对于对象是 never instantiated but always explicitly applied either via call
or apply
的东西是编写 mixin 的可能方法之一。实际上,该示例显示了 the most classic purely function-based mixin 模式之一。
更多 ... (自我推销) ...
注意 ...需要注意的是,使用类构造函数作为 mixin 只适用于纯函数。真正/真实的类(基于语法的)构造函数不能apply
ed/call
ed,而只能通过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
上下文中执行函数,该上下文必须作为方法的第一个参数传递。因此,对于给定的示例,确实将 this
和 name
分配给作为 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, name, 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 Food)
);
console.log(
'(item instanceof Object) ?',
(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
随时应用于任何对象,从而调用前者作为应用上下文中的方法。
答案 2 :(得分:1)
您可能需要考虑以下片段:
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, name, price) {
obj.name = name;
obj.price = price;
}
function Food(name, price) {
setProductProperties(this, name, price);
}
const item = new Food('cheese', 50);
绝对等同于您问题中的代码
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);
它们都有相同的结果 - 一个具有 item
和 .name
属性的 .price
对象。区别仅在于它们如何实现这一点,通过函数调用具有不同的抽象级别。使用构造函数可以更轻松地实例化具有相同形状的多个对象,只需在一个地方定义该形状。