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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 07:07:23  来源:igfitidea点击:

Adding new properties to constructor function without .prototype

javascript

提问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 clogis their prototype?

这不会被clog作为原型的对象继承吗?

回答by T.J. Crowder

Instances created by a constructor function (clogin your case) inherit a reference to the clog.prototypeobject. So if you add a property to clog.prototype, it will show up on instances. If you add a property to clogitself, 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 Foowould 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 prototypesimply points to the constructor object?

是不是prototype简单地指向构造函数对象?

No, Fooand Foo.prototypeare completely distinct objects. Foois 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 constructorproperty that points back to Foo. It's Foo.prototype, not Foo, that instances created via new Fooget as their prototype. Foo's only role is to create objects that use Foo.prototypeas their prototype. (Actually, in Foo's case, it just initializesthose objects; they're createdby the newoperator. With a traditional function like Foo, newcreates the object. If this code were using ES2015+ classsyntax, newwouldn't create the object, it would leave that to Foo[if Foowere a base class constructor] or Foo's ultimate base class [if Foowere a subclass constructor].)

不,Foo并且Foo.prototype是完全不同的对象。Foo是一个函数对象,它像所有函数对象一样可以有属性。其中一个Foo属性是prototype,它是一个非函数对象,除了constructor指向Foo. 这Foo.prototypeFoo,它通过创建的实例new Foo获取他们的原型。Foo的唯一作用是创建Foo.prototype用作其原型的对象。(实际上,在Foo's 的情况下,它只是初始化这些对象;它们是由操作符创建new。使用像 一样的传统函数Foonew创建对象。如果此代码使用 ES2015+class语法,new不会创建对象,它会将其留给Foo[如果Foo是基类构造函数] 或Foo的最终基类 [如果Foo是子类构造函数]。)

If I do Foo.newProp = "new addition"why is f.newProp => undefined?

如果我这样做Foo.newProp = "new addition"是为什么f.newProp => undefined

(To avoid confusion, I've changed Foo.new = ...to Foo.newProp = ...above, since newis 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.newProphas virtually nothing to do with f. You canfind it, on f.constructor.newProp, since f.constructoris Foo.

因为Foo.newPropf. 您可以在 上找到它f.constructor.newProp,因为f.constructorFoo

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 fobject (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" |
                                  +????????????????????+

fnow 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.charliefirst. Here's what the engine does with f.charlie:

我们先来看看f.charlie。这是引擎的作用f.charlie

  1. Does fhave its own property called "charlie"?
  2. Yes; use the value of that property.
  1. f没有自己的属性叫"charlie"
  2. 是的; 使用该属性的值。

Simple enough. Now let's look at how the engine handles f.bar:

足够简单。现在让我们看看引擎是如何处理的f.bar

  1. Does fhave its own property called "bar"?
  2. No; does fhave a prototype?
  3. Yes; does f's prototype have a property called "bar"?
  4. Yes; use the value of that property.
  1. f没有自己的属性叫"bar"
  2. 不; 确实f有原型?
  3. 是的; 确实f的原型呼吁属性"bar"
  4. 是的; 使用该属性的值。

So there's a big difference between f.charlieand f.bar: fhas 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.charlieand之间有很大的区别f.barf自己的属性叫做charlie,但是继承属性叫做bar。如果f的原型对象没有被调用的属性bar它的原型对象(在本例中为Object.prototype)将被检查,依此类推,直到我们用完原型。

You can test whether a property is an "own" property, btw, using the hasOwnPropertyfunction 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 then var ilya = new Person('ilya', 'D')how does it resolves the inner nameproperties?

我制作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 Personthat's part of the new Person(...)expression, thisrefers to the newly-generated object that will be returned by the newexpression. 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 pobject:

换句话说,这两个示例产生了完全相同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 newoperation works is:

99.9999% 的情况下,您不想从构造函数中返回任何内容。该方式new操作的工作原理是:

  1. A new blank object is created.
  2. It gets assigned a prototype from the constructor's prototypeproperty.
  3. The constructor is called such that thisrefers to the new object.
  4. If the constructor doesn't return anything, or returns something other than an object, the result of the newexpression is the object created in step 1.
  5. If the constructor function returns an object, the result of the newoperation is that object instead.
  1. 创建一个新的空白对象。
  2. 它从构造函数的prototype属性中获得一个原型。
  3. 调用构造函数以this引用新对象。
  4. 如果构造函数不返回任何内容,或返回对象以外的内容,则new表达式的结果是在步骤 1 中创建的对象。
  5. 如果构造函数返回一个对象,则new操作的结果是该对象。

So in your case, since console.logdoesn't return anything, you just remove the returnkeyword 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 alertfunction and assigning the result of it to a property called alerton clog.prototype. Since alertdoesn't return anything, it's exactly equivalent to:

您正在调用alert函数并将其结果分配给名为alerton的属性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 alertproperty 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 Clograther than clog. Again, though, this is just style.

这只是风格,但它绝对是标准的:构造函数(用于与 一起使用的函数new)应该以大写字母开头,Clog而不是clog. 不过,这只是风格。

回答by David Hellsing

Adding a clog.alertfunction would simply a attach static function to the clogobject. 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.alertwill make the new clog();object you create inherit the function, and you will also have access to the instance inside using the thiskeyword.

添加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.

添加到构造函数的任何属性都将充当静态属性,只能通过引用构造函数对象(即函数)而不使用它的任何实例对象来访问。它就像一个类属性而不是一个实例属性。