在JavaScript中,构造函数和作为构造函数调用的返回对象的函数之间有什么区别?
我知道这不是推荐的方法,但是如果我声明以下函数,然后将它们作为构造函数调用,那么结果对象之间会有什么区别(如果有的话)在JavaScript中,构造函数和作为构造函数调用的返回对象的函数之间有什么区别?,javascript,function,constructor,Javascript,Function,Constructor,我知道这不是推荐的方法,但是如果我声明以下函数,然后将它们作为构造函数调用,那么结果对象之间会有什么区别(如果有的话) function Something() { this.foo = "bar"; } function something2() { var that = {}; that.foo = "bar"; return that; } var x = new Something(); var y = new something2(); var z
function Something() {
this.foo = "bar";
}
function something2() {
var that = {};
that.foo = "bar";
return that;
}
var x = new Something();
var y = new something2();
var z = something2();
也就是说,x
、y
和z
之间的区别是什么
something2
不是编写构造函数的更好方法吗,因为无论您是否使用new
都不会影响函数的结果
顺便说一句,
something2
应该在这里大写吗?(我假设不是因为Crockford对大小写如此坚定,因为函数会破坏全局名称空间…在第二种情况下,返回的对象不会从构造函数继承任何内容,因此这样使用它没有什么意义
> var x = new Something();
> var y = new something2();
> var z = something2();
也就是说,这里的x、y和z有什么不同
x
继承自Something
,其中既不是y
也不是z
继承自something2
写构造函数不是更好的方法吗,
因为无论你是否使用新的都不会影响测试结果
功能
调用something2
作为构造函数是没有意义的,因为它返回的对象不是分配给它的this
的新构造对象,它继承自something2.prototype
,这是其他人在调用new something2()
时可能期望得到的
顺便说一句,这里应该大写一些东西吗?(我想从那以后就不会了
Crockford非常坚持大写,因为函数将
删除全局命名空间…)
不,因为将其称为构造函数有点毫无意义,因此将其描述为构造函数会产生误导。简而言之:
new something2() instanceof something2 === false
相关地,如果您扩展示例以使用prototype属性
Something.prototype.method = function () { };
something2.prototype.method = function () { };
在后一种情况下,您会发现原型不是继承的:
typeof (new Something()).method === "function"
type (new something2()).method === "undefined"
真正的答案是,你正在利用完全不同的底层机制。使用
new
调用调用该机制,该机制涉及根据构造函数的.Prototype
属性设置[[Prototype]]属性
但是在[[Construct]]算法的步骤8-10中发生了一件有趣的事情:在设置一个新的空对象,然后附加它的[[Prototype]]之后,它对实际的构造函数执行[[Call]],使用这个新的空加上Prototype对象作为this
。然后,在第9步中,如果发现构造函数返回了一些东西——它扔掉了原型绑定,作为-这个花了所有时间设置的
对象传递
注意:您可以使用对象访问对象的[[Prototype]](这不同于构造函数的.Prototype
)。getPrototypeOf
:
Object.getPrototypeOf(new Something()) === Something.prototype // steps 5 & 6
Object.getPrototypeOf(new something2()) === Object.prototype // default
要回答一些元问题:
- 不,不要大写
,因为它是工厂函数而不是构造函数。如果某个内容是大写的,则它应该具有构造函数语义,例如something2
新的A()实例A
- 如果您担心破坏全局名称空间的危险,那么应该开始使用,方法是将
“use strict”代码>位于文件的顶部。strict模式的许多好的清理方法之一是
默认为此
,而不是全局对象,因此,例如,在构造函数尝试将属性附加到未定义的
时,调用未添加未定义的
的构造函数将导致错误新
- 工厂函数(又名“闭包模式”)通常是构造函数和类的合理替代品,只要您(a)不使用继承;(b) 不要构造太多该对象的实例。后者是因为,在闭包模式中,您将每个方法的一个新实例附加到每个新创建的对象,这对内存使用不是很好。IMO,闭包模式的最大回报是使用的能力(这是一个,不要让任何人告诉你:P)
关键字
)运行以下步骤:
prototype
属性中的对象此
是新对象)return
语句)y
还是z
都不是某个事物的实例2
,也不是从该原型继承的。有这样的函数,是的,但它们不应该被称为构造函数(不使用大写字母命名,不使用new
调用)。它们属于工厂模式
如果您想要一个无需新代码即可执行的构造函数,请使用该代码:
function Something(params) {
if (! this instanceof Something)
return new Something(params);
// else use "this" as usual
this.foo = "bar";
...
}
我认为最重要的是返回对象的原型
function Something() {
this.foo = "bar";
}
Something.prototype = {
// Something prototype code
hello: function(){
//...
}
}
function something2() {
var that = {};
that.foo = "bar";
return that;
}
something2.prototype = {
// something2 prototype code
greetings : function() {
//...
}
}
var x = new Something();
var y = new something2();
var z = something2();
typeof x.hello === function // should be true
typeof y.greetings === undefined // should be true
typeof z.greetings === undefined // should be true
换句话说,我要说的是,您不是在用某种东西实例化对象,而是在创建从对象继承的纯新对象
var that = {};
这相当于
var that = new Object();
对克罗克福德先生要有点警惕。虽然他有很多好话要说,但他确实有一些不同意的意见。第二种方法中的“新”也是可选的(或实际上不需要),但如果在第一种方法中被忽略,就会把事情搞砸(这个===窗口)@Matt