如何从仅调用另一个构造函数的函数实例化新对象?
How is a new object instantiated from a function that only invokes another constructor function?
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
函数实例化,但它只包含另一个函数,然后使用传递 this
的 call()
方法调用哪个指的是新实例化的对象? Product
函数如何成为 item
对象的构造函数?我不明白传输是如何发生的,因为 Food
不是构造函数,并且 Product.call()
不 return Product
函数的内容Food
函数构造函数。
有人可以给我解释一下吗?
当您使用 new
关键字调用函数时,它会创建一个对象实例。让我们称之为 this
。在函数内部,我们可以将内容分配给 this
,因此它将成为 this
.
的属性
每个函数本质上都可以用作构造函数,但如果我们不向 this
分配任何内容,它就不会有任何属性。因此,在您的情况下,我们使用 Food
函数作为构造函数(在 new
关键字的帮助下),而不是在函数中手动将内容分配给 this
,我们调用以 this
作为我们希望将属性分配给的对象的不同函数。
Product
和 Food
乍一看都像 classic 构造函数。让我们看看实例化从哪里开始......new Food
利用Food
作为构造函数,因此,在construction/instantiation时,Food
的this
上下文已经引用到 Food
个实例。后者通过非实例化 Product.call
作为 thisArgs
进入 Product
的 call/invocation 时间。因此,现在有一个 Food
实例被 Product
处理为 this
上下文,它 add/augment 属性 name
和 price
非常 Food
实例。
看起来像构造函数(具有 this
上下文)但却是 never instantiated but always explicitly applied either via call
or apply
to an object is one of the possible ways of writing a mixin. Actually the example shows one of the most classic purely function-based mixin 模式的东西。
更多 ... (自我推销) ...
- How to use mixins properly in Javascript
注意 ...需要注意的是,将类似构造函数的函数用作混合函数确实只适用于纯函数。 True/real class(基于语法)构造函数 函数不能是apply
ed/call
ed, but only instantiated via the new
operator.
下面示例的日志记录确实证明了上述解释...
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)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
编辑:
OP 的问题
I get that this
inside Food()
refers to the new instance item
, but I'm not getting how is it that when you pass this
to Product()
, now the this.name
inside Product()
gets assigned to the passed this
? First of all, I thought call()
changes the object owner, but Product()
is not instantiated yet, so how can it have a new object owner?
A.
不要被Product
的命名和大写字母搞糊涂了。人们需要将其视为具有 this
上下文 的普通 函数,因此 方法 ,仍然 “免费floating 因为它本身没有分配给对象(永远不会)。
甚至可以将其重命名为 assignProductFeatures
。使用 call
/ apply
(显然 OP 甚至采用了前者的示例)确实在必须作为方法的第一个参数传递的 this
上下文中执行函数。因此,对于给定的示例,确实将 name
和 price
分配给作为 this
上下文提供的任何 object/instance。
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)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
编辑:
OP 的问题
For this.name = name
inside Product()
to be assigned to the passed object referenced by this
, then the Product()
function must be acting as a constructor to the item
instance, otherwise, how are the properties defined inside Product()
referenced by this
inside Food()
? call(this)
invokes Product()
with item
as its new object owner, but item
does not have any properties, and Food()
is not instantiating any object... I can't wrap my head around this!!!! I get what you're saying to me, but I can't understand the mechanics, and how it's all working!
来自你所有的问题...
"the Product()
function must be acting as a constructor to the item instance"
...不,一点也不,因为...
"Call()
is supposed to change the object owner"
...完全正确,但只是在委托函数's/method的调用时间临时恰好一次...
"... if Product() is not even instantiated?"
...不需要实例化。查看上面的示例,我试图让您将 Product
视为未绑定方法,它通过显式调用 call
/apply
及时应用于任何对象,从而调用前者作为应用上下文中的方法。
您可能需要考虑以下片段:
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);
它们都有相同的结果 - 具有属性 .name
和 .price
的 item
对象。不同之处仅在于它们如何通过函数调用实现不同级别的抽象。拥有构造函数只会让实例化具有相同形状的多个对象变得更容易,只在一个地方定义该形状。
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
函数实例化,但它只包含另一个函数,然后使用传递 this
的 call()
方法调用哪个指的是新实例化的对象? Product
函数如何成为 item
对象的构造函数?我不明白传输是如何发生的,因为 Food
不是构造函数,并且 Product.call()
不 return Product
函数的内容Food
函数构造函数。
有人可以给我解释一下吗?
当您使用 new
关键字调用函数时,它会创建一个对象实例。让我们称之为 this
。在函数内部,我们可以将内容分配给 this
,因此它将成为 this
.
每个函数本质上都可以用作构造函数,但如果我们不向 this
分配任何内容,它就不会有任何属性。因此,在您的情况下,我们使用 Food
函数作为构造函数(在 new
关键字的帮助下),而不是在函数中手动将内容分配给 this
,我们调用以 this
作为我们希望将属性分配给的对象的不同函数。
Product
和 Food
乍一看都像 classic 构造函数。让我们看看实例化从哪里开始......new Food
利用Food
作为构造函数,因此,在construction/instantiation时,Food
的this
上下文已经引用到 Food
个实例。后者通过非实例化 Product.call
作为 thisArgs
进入 Product
的 call/invocation 时间。因此,现在有一个 Food
实例被 Product
处理为 this
上下文,它 add/augment 属性 name
和 price
非常 Food
实例。
看起来像构造函数(具有 this
上下文)但却是 never instantiated but always explicitly applied either via call
or apply
to an object is one of the possible ways of writing a mixin. Actually the example shows one of the most classic purely function-based mixin 模式的东西。
更多 ... (自我推销) ...
- How to use mixins properly in Javascript
注意 ...需要注意的是,将类似构造函数的函数用作混合函数确实只适用于纯函数。 True/real class(基于语法)构造函数 函数不能是apply
ed/call
ed, but only instantiated via the new
operator.
下面示例的日志记录确实证明了上述解释...
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)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
编辑:
OP 的问题
I get that
this
insideFood()
refers to the new instanceitem
, but I'm not getting how is it that when you passthis
toProduct()
, now thethis.name
insideProduct()
gets assigned to the passedthis
? First of all, I thoughtcall()
changes the object owner, butProduct()
is not instantiated yet, so how can it have a new object owner?
A.
不要被Product
的命名和大写字母搞糊涂了。人们需要将其视为具有 this
上下文 的普通 函数,因此 方法 ,仍然 “免费floating 因为它本身没有分配给对象(永远不会)。
甚至可以将其重命名为 assignProductFeatures
。使用 call
/ apply
(显然 OP 甚至采用了前者的示例)确实在必须作为方法的第一个参数传递的 this
上下文中执行函数。因此,对于给定的示例,确实将 name
和 price
分配给作为 this
上下文提供的任何 object/instance。
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)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
编辑:
OP 的问题
For
this.name = name
insideProduct()
to be assigned to the passed object referenced bythis
, then theProduct()
function must be acting as a constructor to theitem
instance, otherwise, how are the properties defined insideProduct()
referenced bythis
insideFood()
?call(this)
invokesProduct()
withitem
as its new object owner, butitem
does not have any properties, andFood()
is not instantiating any object... I can't wrap my head around this!!!! I get what you're saying to me, but I can't understand the mechanics, and how it's all working!
来自你所有的问题...
"the
Product()
function must be acting as a constructor to the item instance"
...不,一点也不,因为...
"
Call()
is supposed to change the object owner"
...完全正确,但只是在委托函数's/method的调用时间临时恰好一次...
"... if Product() is not even instantiated?"
...不需要实例化。查看上面的示例,我试图让您将 Product
视为未绑定方法,它通过显式调用 call
/apply
及时应用于任何对象,从而调用前者作为应用上下文中的方法。
您可能需要考虑以下片段:
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);
它们都有相同的结果 - 具有属性 .name
和 .price
的 item
对象。不同之处仅在于它们如何通过函数调用实现不同级别的抽象。拥有构造函数只会让实例化具有相同形状的多个对象变得更容易,只在一个地方定义该形状。