[英]Adding new properties to constructor function without .prototype
when I have function I want to use as a constructor, say: 当我有函数我想用作构造函数时,说:
function clog(x){
var text = x;
return console.log(text );
}
And I have made some instances of it 我已经做了一些实例
var bla = new clog();
Now I want to add new functionality it, so I would use 现在我想添加新的功能,所以我会用
clog.prototype.alert = alert(text);
what would be the difference if I simply do: 如果我这样做会有什么不同:
clog.alert = alert(text);
Would that not be inherited by the objects that clog
is their prototype? clog
的对象是否会继承它们的原型?
Instances created by a constructor function ( clog
in your case) inherit a reference to the clog.prototype
object. 由构造函数创建的实例(在您的情况下为clog
)继承对clog.prototype
对象的引用。 So if you add a property to clog.prototype
, it will show up on instances. 因此,如果向clog.prototype
添加属性,它将显示在实例上。 If you add a property to clog
itself, it will not show up on instances. 如果添加一个属性来clog
自身,它将不会显示在实例上。
There are some issues with your quoted code, so let's look at an abstract example: 引用代码存在一些问题,让我们看一个抽象的例子:
function Foo() {
}
Foo.prototype.bar = "I'm bar on Foo.prototype";
Foo.bar = "I'm bar on Foo";
var f = new Foo();
console.log(f.bar); // "I'm bar on Foo.prototype"
// E.g., `f` inherits from `Foo.prototype`, not `Foo`
// And this link is live, so:
Foo.prototype.charlie = "I'm charlie on Foo.prototype";
console.log(f.charlie); // "I'm charlie on Foo.prototype";
From your comment below: 来自您的评论如下:
I don't understand why new properties added directly to
Foo
would be ignored by the prototype chain? 我不明白为什么原型链会忽略直接添加到Foo
新属性?
Because it's Foo.prototype
, not Foo
, that is the prototype for objects created via new Foo()
. 因为它是Foo.prototype
,而不是Foo
,这是通过new Foo()
创建的对象的原型。
isn't
prototype
simply points to the constructor object? 是不是prototype
只是指向构造函数对象?
No, Foo
and Foo.prototype
are completely distinct objects. 不, Foo
和Foo.prototype
是完全不同的对象。 Foo
is a function object, which like all function objects can have properties. Foo
是一个函数对象,它像所有函数对象一样可以拥有属性。 One of Foo
's properties is prototype
, which is a non-function object that's initially blank other than a constructor
property that points back to Foo
. Foo
的一个属性是prototype
,它是一个非函数对象,除了指向Foo
的constructor
属性之外,它最初是空白的。 It's Foo.prototype
, not Foo
, that instances created via new Foo
get as their prototype. 它是Foo.prototype
,而不是Foo
,通过new Foo
创建的实例作为他们的原型。 Foo
's only role is to create objects that use Foo.prototype
as their prototype. Foo
的唯一作用是创建使用Foo.prototype
作为原型的对象。 (Actually, in Foo
's case, it just initializes those objects; they're created by the new
operator. With a traditional function like Foo
, new
creates the object. If this code were using ES2015+ class
syntax, new
wouldn't create the object, it would leave that to Foo
[if Foo
were a base class constructor] or Foo
's ultimate base class [if Foo
were a subclass constructor].) (实际上,在Foo
的情况下,它只是初始化那些对象;它们是由new
运算符创建的。使用像Foo
这样的传统函数, new
会创建对象。如果此代码使用ES2015 + class
语法,则new
不会创建对象,它会留给Foo
[如果Foo
是基类构造函数]或Foo
的最终基类[如果Foo
是子类构造函数]。)
If I do
Foo.newProp = "new addition"
why isf.newProp => undefined
? 如果我做Foo.newProp = "new addition"
为什么f.newProp => undefined
?
(To avoid confusion, I've changed Foo.new = ...
to Foo.newProp = ...
above, since new
is a keyword. While you can use it like you did as of ES5, it's best not to.) (为了避免混淆,我将Foo.new = ...
改为Foo.newProp = ...
上面,因为new
是一个关键字。虽然你可以像使用ES5一样使用它,但最好不要这样做。)
Because Foo.newProp
has virtually nothing to do with f
. 因为Foo.newProp
几乎与f
无关。 You can find it, on f.constructor.newProp
, since f.constructor
is Foo
. 你可以在f.constructor.newProp
上找到它,因为f.constructor
是Foo
。
Some ASCII-art: 一些ASCII艺术:
Given this code: 鉴于此代码:
function Foo() {
}
Foo.prototype.bar = "I'm bar on Foo.prototype";
Foo.bar = "I'm bar on Foo";
we have these objects with these properties (some omitted for clarity): 我们有这些具有这些属性的对象(为清楚起见,省略了一些):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | V +−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ +−−>| [String] | | | Foo [Function] | | +−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ | | "I'm bar on Foo" | | | bar |−−−−+ +−−−−−−−−−−−−−−−−−−+ | | prototype |−−−−+ | +−−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−+ | | | V | +−−−−−−−−−−−−−+ | | [Object] | | +−−−−−−−−−−−−−+ | | constructor |−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | bar |−−−−−>| [String] | +−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | "I'm bar on Foo.prototype" | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
Now if we do 如果我们这样做
var f = new Foo();
we have (new stuff in bold ): 我们有( 粗体新内容):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | V +−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ +−−>| [String] | | | Foo [Function] | | +−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ | | "I'm bar on Foo" | | | bar |−−−−+ +−−−−−−−−−−−−−−−−−−+ | | prototype |−−−−+ | +−−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−+ | | | V | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−+ | | f [Object] | +−−−−−>| [Object] | | +−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ | | [[Prototype]] |−−−−−−−−−−+ | constructor |−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−+ | bar |−−−−>| [String] | +−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | "I'm bar on Foo.prototype" | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
([[Prototype]] is an object's internal field referring to its prototype. This is accessible via Object.getPrototypeOf
[or __proto__
on JavaScript engines on web browsers, but don't use __proto__
, it's just for backward compatibility with old SpiderMonkey-specific code.) ([[Prototype]]是一个对象的内部字段,引用它的原型。这可以通过Web浏览器上的JavaScript引擎上的Object.getPrototypeOf
[或__proto__
访问,但不要使用__proto__
,它只是为了向后兼容旧的SpiderMonkey特有的码。)
Now suppose we do this: 现在假设我们这样做:
f.charlie = "I'm charlie on f";
All that changes is the f
object (new stuff in bold ): 所有改变都是f
对象( 粗体的新东西):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | V +−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ +−−>| [String] | | | Foo [Function] | | +−−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ | | "I'm bar on Foo" | | | bar |−−−−+ +−−−−−−−−−−−−−−−−−−+ | | prototype |−−−−+ | +−−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−+ | | | V | +−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−+ | | f [Object] | +−−−−−>| [Object] | | +−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ | | [[Prototype]] |−−−−−−−−−−+ | constructor |−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | charlie |−−−−−−−−−−+ | bar |−−−−−>| [String] | +−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | "I'm bar on Foo.prototype" | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−−−−+ +−−−−−>| [String] | +−−−−−−−−−−−−−−−−−−−−+ | "I'm charlie on f" | +−−−−−−−−−−−−−−−−−−−−+
f
now has its own property, called charlie
. f
现在有自己的财产,叫做charlie
。 This means that these two statements: 这意味着这两个陈述:
console.log(f.charlie); // "I'm charlie on f"
console.log(f.bar); // "I'm bar on Foo.prototype"
Get processed slightly differently. 处理略有不同。
Let's look at f.charlie
first. 我们先来看看f.charlie
。 Here's what the engine does with f.charlie
: 这是引擎对f.charlie
:
f
have its own property called "charlie"
? f
有自己的属性叫"charlie"
吗? Simple enough. 很简单。 Now let's look at how the engine handles f.bar
: 现在让我们看一下引擎如何处理f.bar
:
f
have its own property called "bar"
? f
有自己的属性叫做"bar"
吗? f
have a prototype? f
有原型吗? f
's prototype have a property called "bar"
? f
的原型是否有一个名为"bar"
的属性? So there's a big difference between f.charlie
and f.bar
: f
has its own property called charlie
, but an inherited property called bar
. 所以f.charlie
和f.bar
之间有很大的区别: f
有自己的属性叫charlie
,但是有一个名为bar
的继承属性。 And if f
's prototype object hadn't had a property called bar
, its prototype object (in this case, Object.prototype
) would be checked, and so on up the chain until we run out of prototypes. 如果f
的原型对象没有名为bar
的属性, Object.prototype
检查其原型对象(在本例中为Object.prototype
),依此类推,直到我们用完原型。
You can test whether a property is an "own" property, btw, using the hasOwnProperty
function that all objects have: 您可以使用所有对象具有的hasOwnProperty
函数来测试属性是否为“自己的”属性btw:
console.log(f.hasOwnProperty("charlie")); // true
console.log(f.hasOwnProperty("bar")); // false
Answering your question from the comments: 从评论中回答你的问题:
I make
function Person(first_name, last_name) {this.first_name = first_name; this.last_name = last_name;}
我创建function Person(first_name, last_name) {this.first_name = first_name; this.last_name = last_name;}
function Person(first_name, last_name) {this.first_name = first_name; this.last_name = last_name;}
and thenvar ilya = new Person('ilya', 'D')
how does it resolves the innername
properties?function Person(first_name, last_name) {this.first_name = first_name; this.last_name = last_name;}
然后var ilya = new Person('ilya', 'D')
它如何解析内部name
属性?
Within the call to Person
that's part of the new Person(...)
expression, this
refers to the newly-generated object that will be returned by the new
expression. 在Person
的调用中,它是new Person(...)
表达式的一部分, this
指的是新生成的对象,它将由new
表达式返回。 So when you do this.prop = "value";
所以当你这样做时this.prop = "value";
, you're putting a property directly on that object, nothing to do with the prototype. ,你把一个属性直接放在那个对象上,与原型无关。
Putting that another way, these two examples result in exactly the same p
object: 换句话说,这两个例子产生完全相同的p
对象:
// Example 1:
function Person(name) {
this.name = name;
}
var p = new Person("Fred");
// Example 2:
function Person() {
}
var p = new Person();
p.name = "Fred";
Here are the issues with the quoted code I mentioned: 以下是我提到的引用代码的问题:
Issue 1: Returning something from a constructor function: 问题1:从构造函数返回一些东西:
function clog(x){
var text = x;
return console.log(text ); // <=== here
}
99.9999% of the time, you don't want to return anything out of a constructor function. 在99.9999%的时间内,您不希望从构造函数中返回任何内容。 The way the new
operation works is: new
操作的工作方式是:
prototype
property. 它从构造函数的prototype
属性中分配了一个原型。 this
refers to the new object. 构造函数被调用,使得this
指的是新的对象。 new
expression is the object created in step 1. 如果构造函数未返回任何内容,或返回除对象之外的其他内容,则new
表达式的结果是在步骤1中创建的对象。 new
operation is that object instead. 如果构造函数返回一个对象,则new
操作的结果是该对象。 So in your case, since console.log
doesn't return anything, you just remove the return
keyword from your code. 因此,在您的情况下,由于console.log
不返回任何内容,您只需从代码中删除return
关键字。 But if you used that return xyz();
但是如果你使用那个return xyz();
construct with a function that returned an object, you'd mess up your constructor function. 使用返回对象的函数构造,你会搞乱你的构造函数。
Issue 2: Calling functions rather than referring to them 问题2:调用函数而不是引用函数
In this code: 在这段代码中:
clog.prototype.alert = alert(text);
you're calling the alert
function and assigning the result of it to a property called alert
on clog.prototype
. 您正在调用 alert
功能并将其结果分配给clog.prototype
上名为alert
的属性。 Since alert
doesn't return anything, it's exactly equivalent to: 由于alert
不会返回任何内容,因此它完全等同于:
alert(text);
clog.prototype.alert = undefined;
...which probably isn't what you meant. ......这可能不是你的意思。 Perhaps: 也许:
clog.prototype.alert = function(text) {
alert(text);
};
There we create a function and assign a reference to it to the alert
property on the prototype. 在那里,我们创建一个函数并将其引用分配给原型上的alert
属性。 When the function is called, it will call the standard alert
. 调用该函数时,它将调用标准alert
。
Issue 3: Constructor functions should be initially capped 问题3:构造函数应该初始上限
This is just style, but it's overwhelmingly standard: Constructor functions (functions meant to be used with new
) should start with an upper case letter, so Clog
rather than clog
. 这只是样式,但它绝对是标准的:构造函数(函数意味着与new
一起使用)应该以大写字母开头,所以Clog
而不是clog
。 Again, though, this is just style. 不过,这只是风格。
Adding a clog.alert
function would simply a attach static function to the clog
object. 添加clog.alert
函数只是将一个静态函数附加到clog
对象。 It will not be inherited and will not have access to the instance created with new clog();
它不会被继承,也不会访问使用new clog();
创建的实例new clog();
in the alert function. 在警报功能中。
Adding clog.prototype.alert
will make the new clog();
添加clog.prototype.alert
将使new clog();
object you create inherit the function, and you will also have access to the instance inside using the this
keyword. 您创建的对象继承了该函数,您还可以使用this
关键字访问该实例。
function John() {
this.id = 1;
}
John.doe = function() {
console.log(this);
console.log(this.id); // undefined
}
John.prototype.doe = function() {
console.log(this);
};
John.doe(); // the John object
var me = new John();
me.doe(); // the instance, inherited from prototype
console.log(me.id); // 1
Any property added to the constructor will act as a static property that can only be accessed by referring to the constructor object (ie, function) and not using any instance object of it. 添加到构造函数的任何属性都将充当静态属性,只能通过引用构造函数对象(即函数)并且不使用它的任何实例对象来访问它。 Its like a Class property and not an instance property. 它类似于Class属性而不是实例属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.