在没有.prototype的情况下向构造函数添加新属性 [英] Adding new properties to constructor function without .prototype

查看:75
本文介绍了在没有.prototype的情况下向构造函数添加新属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我有函数时我想用作构造函数,比如说:

when I have function I want to use as a constructor, say:

function clog(x){
    var text = x;
    return console.log(text );
}

我已经做了一些实例

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);

不会被 clog 是他们的原型吗?

Would that not be inherited by the objects that clog is their prototype?

推荐答案

构造函数创建的实例( clog 在你的情况下)继承对 clog.prototype 对象的引用。因此,如果向 clog.prototype 添加属性,它将显示在实例上。如果您将属性添加到 clog 本身,它将不会显示在实例上。

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.

有一些问题你引用的代码,让我们看一个抽象的例子:

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";

从下面的评论中:


我不明白为什么原型链会忽略直接添加到 Foo 的新属性?

因为它是 Foo.prototype ,而不是 Foo ,这是通过 new Foo()创建的对象的原型。

Because it's Foo.prototype, not Foo, that is the prototype for objects created via new Foo().


不是 prototype 只是指向构造函数对象?

isn't prototype simply points to the constructor object?

不, Foo Foo.prototype 是完全不同的对象。 Foo 是一个函数对象,它与所有函数对象一样可以具有属性。 Foo 的一个属性是 prototype ,这是一个非函数对象,除了<$之外最初是空白的c $ c> constructor 指向 Foo 的属性。它是 Foo.prototype ,而不是 Foo ,它参与了JavScript的原型继承。 Foo 唯一的作用是创建对象(实际上,初始化对象; new 运算符创建它们)使用 Foo.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 participates in JavScript's prototypical inheritance. Foo's only role is to create objects (well, actually, to initialize objects; the new operator creates them) that use Foo.prototype as their prototype.


如果我 Foo.newProp =new addition为什么 f.newProp => undefined

(为避免混淆,我改变了 Foo.new = ... Foo.newProp = ... 以上,因为 new 是一个关键字。虽然可以像在ES5那样使用它,但最好不要这样做。)

(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.newProp 几乎与 f 无关。你可以在 f.constructor.newProp 上找到它,因为 f.constructor Foo

Because Foo.newProp has virtually nothing to do with f. You can find it, on f.constructor.newProp, since f.constructor is Foo.

一些ASCII艺术:

鉴于此代码:

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" |
                                                    +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

现在,如果我们这样做

var f = new Foo();

我们有(粗体的新内容):


        +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
        |                                       |
        V                 +−−−−−−−−−−−−−−−−−−+  |
+−−−−−−−−−−−−−−−−+    +−−>| [String]         |  |
| Foo [Function] |    |   +−−−−−−−−−−−−−−−−−−+  |
+−−−−−−−−−−−−−−−−+    |   | "I'm bar on Foo" |  |
| bar            |−−−−+   +−−−−−−−−−−−−−−−−−−+  |
| prototype      |−−−−+                         |
+−−−−−−−−−−−−−−−−+    |                         |
                      +−−−−−−−−−−+              |
                                 |              |
                                 V              |
+−−−−−−−−−−−−+                 +−−−−−−−−−−−−−+  |
| f [Object] |          +−−−−−>| [Object]    |  |
+−−−−−−−−−−−−+          |      +−−−−−−−−−−−−−+  |
| __proto__  |−−−−−−−−−−+      | constructor |−−+   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
+−−−−−−−−−−−−+                 | bar         |−−−−−>| [String]                   |
                               +−−−−−−−−−−−−−+      +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
                                                    | "I'm bar on Foo.prototype" |
                                                    +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+

__ proto __ 不是字面上的属性名称(至少在大多数引擎上都没有),但它是对象与其原型对象的内部链接。

__proto__ isn't literally a property name (at least not on most engines), but it's the object's internal link to its prototype object.

现在假设我们这样做:

f.charlie = "I'm charlie on f";

所有更改都是 f 对象( 粗体中的新内容:

All that changes is the f object (new stuff in bold):


        +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
        |                                       |
        V                 +−−−−−−−−−−−−−−−−−−+  |
+−−−−−−−−−−−−−−−−+    +−−>| [String]         |  |
| Foo [Function] |    |   +−−−−−−−−−−−−−−−−−−+  |
+−−−−−−−−−−−−−−−−+    |   | "I'm bar on Foo" |  |
| bar            |−−−−+   +−−−−−−−−−−−−−−−−−−+  |
| prototype      |−−−−+                         |
+−−−−−−−−−−−−−−−−+    |                         |
                      +−−−−−−−−−−+              |
                                 |              |
                                 V              |
+−−−−−−−−−−−−+                 +−−−−−−−−−−−−−+  |
| f [Object] |          +−−−−−>| [Object]    |  |
+−−−−−−−−−−−−+          |      +−−−−−−−−−−−−−+  |
| __proto__  |−−−−−−−−−−+      | constructor |−−+   +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| charlie    |−−−−−−−−−−+      | bar         |−−−−−>| [String]                   |
+−−−−−−−−−−−−+          |      +−−−−−−−−−−−−−+      +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
                        |                           | "I'm bar on Foo.prototype" |
                        |                           +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
                        |
                        |      +−−−−−−−−−−−−−−−−−−−−+
                        +−−−−−>| [String]           |
                               +−−−−−−−−−−−−−−−−−−−−+
                               | "I'm charlie on f" |
                               +−−−−−−−−−−−−−−−−−−−−+

f 现在有拥有属性,名为 charlie 。这意味着这两个语句:

f now has its own property, called 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"

处理略有不同。

让我们先看看 f.charlie 。这是引擎用 f.charlie 做的事情:

Let's look at f.charlie first. Here's what the engine does with f.charlie:


  1. f 有自己的属性叫charlie

  2. 是;使用该属性的值。

  1. Does f have its own property called "charlie"?
  2. Yes; use the value of that property.

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

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


  1. f 有自己的属性名为bar

  2. 否; f 有原型吗?

  3. 是; f 的原型是否有一个名为bar的属性

  4. 是;使用该属性的值。

  1. Does f have its own property called "bar"?
  2. No; does f have a prototype?
  3. Yes; does f's prototype have a property called "bar"?
  4. Yes; use the value of that property.

因此 f.charlie f.bar f 拥有属性名为 charlie ,但继承的属性名为 bar 。如果 f 的原型对象没有名为 bar 的属性,将检查原型对象(在本例中为 Object.prototype ),依此类推,直到我们用完原型。

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

您可以使用所有对象具有的 hasOwnProperty 函数来测试属性是否为自己的属性btw:

You can test whether a property is an "own" property, btw, using the hasOwnProperty function that all objects have:

console.log(f.hasOwnProperty("charlie")); // true
console.log(f.hasOwnProperty("bar"));     // false

从评论中回答你的问题:

Answering your question from the comments:


我使函数Person(first_name,last_name){this.first_name = first_name; this.last_name = last_name;} 然后 var ilya = new Person('ilya','D')它如何解析内部 name properties?

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 name properties?

Person 这是新人(...)表达式的一部分,是指新的生成的对象,将由 new 表达式返回。因此当你执行 this.prop =value; 时,你将一个属性直接放在该对象上,与原型无关。

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.

换句话说,这两个例子导致完全相同的 p 对象:

Putting that another way, these two examples result in exactly the same p object:

// 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:

问题1:从构造函数返回一些东西:

Issue 1: Returning something from a constructor function:

function clog(x){
    var text = x;
    return console.log(text ); // <=== here
}

99.9999%的时间,你不要我想从构造函数中返回任何东西。 new 操作的工作方式是:

99.9999% of the time, you don't want to return anything out of a constructor function. The way the new operation works is:


  1. 创建一个新的空白对象。

  2. 从构造函数的原型属性中分配一个原型。

  3. 调用构造函数这样这个引用新对象。

  4. 如果构造函数没有返回任何内容,或者返回 object new 表达式的结果是在步骤1中创建的对象。

  5. 如果构造函数返回一个对象, new 操作的结果是该对象。

  1. A new blank object is created.
  2. It gets assigned a prototype from the constructor's prototype property.
  3. The constructor is called such that this refers to the new object.
  4. 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.
  5. If the constructor function returns an object, the result of the new operation is that object instead.

因此,在您的情况下,由于 console.log 不返回任何内容,您只需从代码中删除 return 关键字。但如果您使用返回对象的函数返回xyz(); 构造,则会破坏构造函数。

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.

问题2:调用函数而不是引用它们

Issue 2: Calling functions rather than referring to them

在此代码中:

clog.prototype.alert = alert(text);

致电 提醒函数并将其结果分配给 clog.prototype 上名为 alert 的属性。由于 alert 不会返回任何内容,因此它完全等同于:

you're calling the 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(text);
clog.prototype.alert = undefined;

...这可能不是你的意思。也许:

...which probably isn't what you meant. Perhaps:

clog.prototype.alert = function(text) {
    alert(text);
};

我们创建一个函数并将其引用分配给<原型上的code> alert 属性。调用该函数时,它将调用标准警报

There we create a 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.

问题3:构造函数应该初始上限

Issue 3: Constructor functions should be initially capped

这只是样式,但它是压倒性地标准:构造函数(函数意味着与<$一起使用) c $ c> new )应以大写字母开头,所以 Clog 而不是 clog 。不过,这只是风格。

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. Again, though, this is just style.

这篇关于在没有.prototype的情况下向构造函数添加新属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆