当我有函数时我想用作构造函数,比如说:
function clog(x){
var text = x;
return console.log(text );
}
我已经做了一些实例
var bla = new clog();
现在我想添加新功能,所以我会使用
clog.prototype.alert = alert(text);
如果我这样做会有什么不同:
clog.alert = alert(text);
clog
是原型的对象不会继承吗?
答案 0 :(得分:45)
由构造函数(在您的情况下为clog
)创建的实例继承对clog.prototype
对象的引用。因此,如果向clog.prototype
添加属性,它将显示在实例上。如果您向clog
本身添加属性,它将不会显示在实例上。
您引用的代码存在一些问题,所以让我们看一个抽象的例子:
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()
创建的对象的原型。
是不是
prototype
只是指向构造函数对象?
不, 如果我 (为避免混淆,我已将 因为 一些ASCII艺术: 鉴于此代码: 我们有这些具有这些属性的对象(为清楚起见,省略了一些): 现在,如果我们这样做 我们有(粗体中的新内容): ([[Prototype]]是一个对象的内部字段,指的是它的原型。这可以通过网络浏览器上的JavaScript引擎上的 现在假设我们这样做: 所有更改都是 处理略有不同。 让我们先看看 足够简单。现在让我们看一下引擎如何处理 您可以测试某个属性是否属于"拥有" property,btw,使用所有对象具有的 从评论中回答你的问题: 我制作 在 换句话说,这两个示例导致完全相同的 以下是我提到的引用代码的问题: 问题1:从构造函数返回内容: 99.9999%的时间,你不想从构造函数中返回任何东西。 因此,在您的情况下,由于 问题2:调用函数而不是引用它们 在此代码中: 您调用 ......这可能不是你的意思。也许: 我们创建一个函数并将其引用分配给原型上的 问题3:构造函数应该初始上限 这只是样式,但它的压倒一切标准:构造函数(与Foo
和Foo.prototype
是完全不同的对象。 Foo
是一个函数对象,它与所有函数对象一样可以具有属性。 Foo
的一个属性是prototype
,这是一个非功能对象,除了constructor
属性之外,它最初是空白的,指向{{1} }}。通过Foo
创建的实例作为原型获得Foo.prototype
,而非Foo
。 new Foo
唯一的作用是创建使用Foo
作为原型的对象。 (实际上,在Foo.prototype
的情况下,它只是初始化这些对象;它们由Foo
运算符创建 使用像new
这样的传统函数,Foo
创建对象。如果此代码使用ES2015 + new
语法,class
将无法创建对象,它会将其留给new
[如果Foo
是基类构造函数]或Foo
的最终基类[如果Foo
是子类构造函数]。)< / p>
Foo
为什么Foo.newProp = "new addition"
?f.newProp => undefined
更改为Foo.new = ...
,因为Foo.newProp = ...
是关键字。而可以像你在ES5那样使用它,它最好不要。) new
几乎与Foo.newProp
无关。您可以<{1}} 找到它,因为f
是f.constructor.newProp
。f.constructor
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| |
V +−−−−−−−−−−−−−−−−−−+ |
+−−−−−−−−−−−−−−−−+ +−−>| [String] | |
| Foo [Function] | | +−−−−−−−−−−−−−−−−−−+ |
+−−−−−−−−−−−−−−−−+ | | "I'm bar on Foo" | |
| bar |−−−−+ +−−−−−−−−−−−−−−−−−−+ |
| prototype |−−−−+ |
+−−−−−−−−−−−−−−−−+ | |
+−−−−−−−−−−+ |
| |
V |
+−−−−−−−−−−−−−+ |
| [Object] | |
+−−−−−−−−−−−−−+ |
| constructor |−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| bar |−−−−−>| [String] |
+−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| "I'm bar on Foo.prototype" |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
Foo
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| |
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" |
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
function Foo() {
}
Foo.prototype.bar = "I'm bar on Foo.prototype";
Foo.bar = "I'm bar on Foo";
[或var f = new Foo();
访问,但不要在&#39 ; t使用Object.getPrototypeOf
,它只是为了与旧的SpiderMonkey特定代码向后兼容。)__proto__
__proto__
对象(粗体中的新内容): +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| |
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.charlie = "I'm charlie on f";
现在有拥有属性,名为f
。这意味着这两个陈述:f
charlie
。以下是引擎对console.log(f.charlie); // "I'm charlie on f"
console.log(f.bar); // "I'm bar on Foo.prototype"
所做的事情:
f.charlie
是否有自己的属性f.charlie
?f
:
"charlie"
是否有自己的属性f.bar
?f
有原型吗?"bar"
的原型是否有一个名为f
?f
和"bar"
之间存在很大差异:f.charlie
的拥有属性名为f.bar
,但是< strong> inherited 属性名为f
。如果charlie
的原型对象没有名为bar
的属性,其原型对象(在本例中为f
)将被检查,依此类推,直到我们用完原型。bar
函数:Object.prototype
hasOwnProperty
然后console.log(f.hasOwnProperty("charlie")); // true
console.log(f.hasOwnProperty("bar")); // false
如何解析内部function Person(first_name, last_name) {this.first_name = first_name; this.last_name = last_name;}
属性?var ilya = new Person('ilya', 'D')
name
表达式的Person
部分调用中,new Person(...)
指的是this
将返回的新生成的对象表达。因此,当您执行new
时,您直接在该对象上放置属性,与原型无关。this.prop = "value";
对象: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";
function clog(x){
var text = x;
return console.log(text ); // <=== here
}
操作的工作方式是:
new
属性中分配一个原型。prototype
引用新对象。this
表达式的结果是在步骤1中创建的对象。new
操作的结果就是该对象。new
没有返回任何内容,您只需从代码中删除console.log
关键字即可。但是如果你使用带有返回对象的函数的return
构造,那么你就搞乱了构造函数。return xyz();
clog.prototype.alert = alert(text);
函数并将其结果分配给alert
上名为alert
的媒体资源。由于clog.prototype
没有返回任何内容,因此它完全等同于:alert
alert(text);
clog.prototype.alert = undefined;
clog.prototype.alert = function(text) {
alert(text);
};
属性。调用该函数时,它将调用标准alert
。alert
一起使用的函数)应该以大写字母开头,所以{{ 1}}而不是new
。但是,这只是风格。
答案 1 :(得分:3)
添加clog.alert
函数只是将clog
对象附加静态函数。它不会被继承,也无法访问在alert函数中使用new clog();
创建的实例。
添加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
答案 2 :(得分:2)
添加到构造函数的任何属性都将充当静态属性,只能通过引用构造函数对象(即函数)并且不使用它的任何实例对象来访问它。 它就像一个Class属性而不是实例属性。