我当然对javascript的内部工作知之甚少,但需要创建一个库并想学习(因此在这里问)。我理解使用闭包并导出到窗口不会污染全局命名空间,但除此之外,它让我感到困惑。
(function() {
var Drop = window.Drop = function() {
var files = [];
var add = function(word) {
files.push(word);
return files;
}
return {
files: files,
add: add
}
}
})()
// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;
// Each has their own state which is what I want.
a.add("file1");
b.add("file2");
c.add("file3");
我在网上搜索过,但发现这个主题的一致性很差。
答案 0 :(得分:2)
第一种方式(Drop()
)只是正常调用该函数,因此this
是全局对象(浏览器环境中为window
)。它做了它的东西然后返回一个对象,正如你所期望的那样。
第二种方式(new Drop()
)创建一个新的Drop
对象,并执行设置为该对象this
的构造函数。但是,您不能在任何地方使用this
并返回从对象文字创建的对象,因此会丢弃Drop
对象,而是返回对象文字。
第三种方式(new Drop
)在语义上与第二种方式相同;这只是一种语法差异。
它们都有自己的状态,因为每次调用Drop
时,它都有自己的一组局部变量,不同于对Drop
的任何其他调用的局部变量。
您可以将代码转换为使用普通new
语法和原型。这有一些优点:即,您只需为add
调用创建Drop
函数一次而不是一次。您修改后的代码可能如下所示:
function Drop() {
this.files = [];
}
Drop.prototype.add = function(word) {
this.files.push(word);
return this.files;
};
但是,通过这样做,您将无法在没有new
的情况下调用它。但是,有一种解决方法:您可以将其添加为function Drop
内的第一行:
if(!(this instanceof Drop)) {
return new Drop();
}
因为当您使用new
调用它时,this
将是Drop
,当您在没有new
的情况下调用它时,this
将成为其他内容与Drop
相比,您可以看到this
是否为Drop
,如果是,则继续初始化;否则,请使用new
重新启动它。
还有另一种语义差异。请考虑以下代码:
var drop = new Drop();
var adder = drop.add;
adder(someFile);
您的代码将在此处运行。基于原型的代码不会,因为this
将是全局对象,而不是drop
。这也有一个解决方法:在构造函数的某个地方,你可以这样做:
this.add = this.add.bind(this);
当然,如果您的图书馆的消费者不打算将该功能从对象中拉出来,您将不需要这样做。此外,您可能需要为没有它的浏览器提取Function.prototype.bind
。
没有。这都是品味问题。
答案 1 :(得分:1)
// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;
在JavaScript中使用new
来调用函数时,函数内的this
值将成为新对象。
但他们在你的情况下是相同的原因是你根本没有使用this
。您正在使用 object literal 语法创建单独的对象,而是返回它,因此new
没有任何影响。
因为每个函数调用都会生成一个新对象,所以每个调用的每个对象都完全不同。
在每个Drop
调用中重新创建分配给对象的函数,因此在封闭变量作用域上创建闭包。因此,每次调用的files
数组都可以连续访问每个调用中的函数。
是。将函数和数组分配给this
,然后删除return
语句。但这将要求使用new
。或者,将函数放在.prototype
的{{1}}对象上,它们将在使用Drop
创建的所有实例之间共享,但保持数组分配给new
构造函数,以便它不被共享。
对于引用数组的原型函数,它们将使用this
。
JavaScript非常灵活。有很多方法可以解决单个问题,每个问题都有自己的优点/缺点。一般来说,它可以归结为利用闭包,原型继承或两者的某种组合。
这是一个完整的原型继承版本。此外,外部this.files
未被使用,因此我将添加一个变量以利用它。
(function() {})()