javascript 向没有 .prototype 的构造函数添加新属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9582341/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Adding new properties to constructor function without .prototype
提问by ilyo
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
作为原型的对象继承吗?
回答by T.J. Crowder
Instances created by a constructor function (clog
in your case) inherit a reference to the clog.prototype
object. So if you add a property to clog.prototype
, it will show up on instances. If you add a property to clog
itself, it will not show up on instances.
由构造函数创建的实例(clog
在您的情况下)继承对clog.prototype
对象的引用。因此,如果您将属性添加到clog.prototype
,它将显示在实例上。如果您向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
is a function object, which like all function objects can have properties. 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
. It's Foo.prototype
, not Foo
, that instances created via new Foo
get as their prototype. Foo
's only role is to create objects that use Foo.prototype
as their prototype. (Actually, in Foo
's case, it just initializesthose objects; they're createdby 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
并且Foo.prototype
是完全不同的对象。Foo
是一个函数对象,它像所有函数对象一样可以有属性。其中一个Foo
属性是prototype
,它是一个非函数对象,除了constructor
指向Foo
. 这Foo.prototype
不Foo
,它通过创建的实例new Foo
获取他们的原型。Foo
的唯一作用是创建Foo.prototype
用作其原型的对象。(实际上,在Foo
's 的情况下,它只是初始化这些对象;它们是由操作符创建的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 youcan 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
. You canfind it, on f.constructor.newProp
, since f.constructor
is Foo
.
因为Foo.newProp
与f
. 您可以在 上找到它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]] 是一个对象的内部字段,指的是它的原型。这可以通过Object.getPrototypeOf
[ 或__proto__
在 web 浏览器上的 JavaScript 引擎上访问,但不要使用__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 ownproperty, called charlie
. This means that these two statements:
f
现在有自己的属性,称为charlie
。这意味着这两个语句:
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. Here's what the engine does with f.charlie
:
我们先来看看f.charlie
。这是引擎的作用f.charlie
:
- Does
f
have its own property called"charlie"
? - Yes; use the value of that property.
- 有
f
没有自己的属性叫"charlie"
? - 是的; 使用该属性的值。
Simple enough. Now let's look at how the engine handles f.bar
:
足够简单。现在让我们看看引擎是如何处理的f.bar
:
- Does
f
have its own property called"bar"
? - No; does
f
have a prototype? - Yes; does
f
's prototype have a property called"bar"
? - Yes; use the value of that property.
- 有
f
没有自己的属性叫"bar"
? - 不; 确实
f
有原型? - 是的; 确实
f
的原型呼吁属性"bar"
? - 是的; 使用该属性的值。
So there's a big difference between f.charlie
and f.bar
: f
has its ownproperty called charlie
, but an inheritedproperty called bar
. And if f
's prototype object hadn't had a property called bar
, itsprototype object (in this case, Object.prototype
) would be checked, and so on up the chain until we run out of prototypes.
所以f.charlie
and之间有很大的区别f.bar
:f
有自己的属性叫做charlie
,但是继承属性叫做bar
。如果f
的原型对象没有被调用的属性bar
,它的原型对象(在本例中为Object.prototype
)将被检查,依此类推,直到我们用完原型。
You can test whether a property is an "own" property, btw, using the hasOwnProperty
function that all objects have:
顺便说一句,您可以使用hasOwnProperty
所有对象都具有的函数来测试属性是否是“自己的”属性:
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;}
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. So when you do this.prop = "value";
, you're putting a property directly on that object, nothing to do with the prototype.
在对表达式Person
的一部分的调用中new Person(...)
,this
指的是表达式将返回的新生成的对象new
。因此,当您这样做时this.prop = "value";
,您将一个属性直接放在该对象上,与原型无关。
Putting that another way, these two examples result in exactlythe 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. The way the new
operation works is:
99.9999% 的情况下,您不想从构造函数中返回任何内容。该方式new
操作的工作原理是:
- A new blank object is created.
- It gets assigned a prototype from the constructor's
prototype
property. - The constructor is called such that
this
refers to the new object. - If the constructor doesn't return anything, or returns something other than an object, the result of the
new
expression is the object created in step 1. - If the constructor function returns an object, the result of the
new
operation is that object instead.
- 创建一个新的空白对象。
- 它从构造函数的
prototype
属性中获得一个原型。 - 调用构造函数以
this
引用新对象。 - 如果构造函数不返回任何内容,或返回对象以外的内容,则
new
表达式的结果是在步骤 1 中创建的对象。 - 如果构造函数返回一个对象,则
new
操作的结果是该对象。
So in your case, since console.log
doesn't return anything, you just remove the return
keyword from your code. But if you used that return xyz();
construct with a function that returned an object, you'd mess up your constructor function.
因此,在您的情况下,由于console.log
不返回任何内容,您只需return
从代码中删除关键字。但是,如果您将该return xyz();
构造与返回对象的函数一起使用,则会弄乱您的构造函数。
Issue 2:Calling functions rather than referring to them
问题 2:调用函数而不是引用它们
In this code:
在这段代码中:
clog.prototype.alert = alert(text);
you're callingthe alert
function and assigning the result of it to a property called alert
on clog.prototype
. Since alert
doesn't return anything, it's exactly equivalent to:
您正在调用该alert
函数并将其结果分配给名为alert
on的属性clog.prototype
。由于alert
不返回任何内容,它完全等同于:
alert(text);
clog.prototype.alert = undefined;
...which probably isn't what you meant. Perhaps:
……这可能不是你的意思。也许:
clog.prototype.alert = function(text) {
alert(text);
};
There we createa function and assign a reference to it to the alert
property on the prototype. When the function is called, it will call the standard alert
.
在那里我们创建了一个函数并将对它的引用分配给alert
原型上的属性。当函数被调用时,它会调用标准的alert
.
Issue 3:Constructor functions should be initially capped
问题 3:构造函数最初应该被封顶
This is just style, but it's overwhelminglystandard: Constructor functions (functions meant to be used with new
) should start with an upper case letter, so Clog
rather than clog
. Again, though, this is just style.
这只是风格,但它绝对是标准的:构造函数(用于与 一起使用的函数new
)应该以大写字母开头,Clog
而不是clog
. 不过,这只是风格。
回答by David Hellsing
Adding a clog.alert
function would simply a attach static function to the clog
object. It will not be inherited and will not have access to the instance created with new clog();
in the alert function.
添加clog.alert
函数只是将静态函数附加到clog
对象。它不会被继承,也无法访问new clog();
在警报函数中创建的实例。
Adding clog.prototype.alert
will make the new clog();
object you create inherit the function, and you will also have access to the instance inside using the this
keyword.
添加clog.prototype.alert
将使new clog();
您创建的对象继承该函数,并且您还可以使用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
回答by Darshan
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.
添加到构造函数的任何属性都将充当静态属性,只能通过引用构造函数对象(即函数)而不使用它的任何实例对象来访问。它就像一个类属性而不是一个实例属性。