在JavaScript中,什么时候需要使用this:
(function(){
//Bunch of code...
})();
在这个问题上:
//Bunch of code...
在JavaScript中,什么时候需要使用this:
(function(){
//Bunch of code...
})();
在这个问题上:
//Bunch of code...
这一切都与变量作用域有关。在自执行函数中声明的变量默认只能在自执行函数内部的代码中使用。这使得可以编写代码,而不必担心变量在JavaScript代码的其他块中如何命名。
例如,正如Alexander在评论中提到的那样:
(function() {
var foo = 3;
console.log(foo);
})();
console.log(foo);
这将首先记录3
,然后在下一个console.log
中抛出错误,因为foo
未定义。
function(){ var foo = 3; alert(foo); }; alert(foo);
所以我还是不理解。 - João Pimentel Ferreira{ let foo = 3 }
呢? - Giulio简约。看起来非常普通,几乎令人感到安慰:
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
然而,如果我在页面中引入一个非常方便的Javascript库,将高级字符转换为其基本级别表示,会怎么样?
等等...什么?
我的意思是,如果有人输入带有某种重音符号的字符,但我只想在程序中使用'英文' 字符A-Z?嗯...西班牙语的'ñ'和法语的'é'字符可以被翻译成基本字符 'n' 和 'e'。
所以有人写了一个全面的字符转换器,我可以将其包含在我的站点中...我把它包含进去了。
问题来了:它里面有一个叫做'name'的函数,和我的函数同名了。
这就是所谓的冲突。我们在同一作用域中声明了两个同名函数。我们要避免这种情况。
因此,我们需要以某种方式对代码进行作用域限定。
Javascript中唯一的作用域限制方式就是将其封装在一个函数中:
function main() {
// We are now in our own sound-proofed room and the
// character-converter library's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
那可能解决我们的问题。现在所有内容都被封装在我们的起始大括号和结束大括号之内,只能从中访问。
我们的函数中有一个函数...看起来很奇怪,但完全合法。
只有一个问题。我们的代码无法正常工作。我们的userName
变量从未在控制台上输出!
我们可以通过在现有代码块后添加对我们的函数的调用来解决此问题...
function main() {
// We are now in our own sound-proofed room and the
// character-converter libarary's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
main();
或者之前!
main();
function main() {
// We are now in our own sound-proofed room and the
// character-converter libarary's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
一个次要的问题是:名称“main”尚未被使用的机会有多大?非常非常渺茫。
我们需要更多的作用域。以及一些自动执行我们的main()函数的方式。
现在我们来谈谈自动执行函数(或自运行、自执行等)。
((){})();
语法非常别扭,但是它可以工作。
当您将函数定义括在括号中,并包括参数列表(另一个括号集!)时,它充当函数调用。
因此,让我们再次查看我们的代码,使用一些自我执行的语法:
(function main() {
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
)();
所以,在大多数你看到的教程中,你现在会被“匿名自执行”或类似术语轰炸。
经过多年的专业发展,我强烈建议为了调试目的命名每个你编写的函数。
当某些问题出现时(它们一定会出现),你将在浏览器中检查回溯。当堆栈跟踪中的条目有名称时,更容易缩小代码问题的范围!
命名空间。JavaScript 的作用域是函数级别的。
我无法相信没有任何答案提到了隐式全局变量。
(function(){})()
的结构并不能防止隐式全局变量,这对我来说是一个更大的问题,详见http://yuiblog.com/blog/2006/06/01/global-domination/
基本上,函数块确保你定义的所有依赖“全局变量”都被限制在你的程序中,但它不能保护你免受定义隐式全局变量的影响。你可以使用类似JSHint或其他工具来建议如何防御这种行为。
更简洁的语法var App = {}
提供了类似的保护级别,在“公共”页面上时可能会包裹在函数块中。(参见Ember.js或SproutCore等实际应用了该结构的库的示例)
至于私有属性,除非你正在创建一个公共框架或库,否则它们有点被高估了。但如果你需要实现它们,Douglas Crockford有一些好的想法。
我已经阅读了所有答案,这里缺少非常重要的内容,我将简述。我需要自执行匿名函数或更好地说"立即调用函数表达式(IIFE)"有两个主要原因:
第一个原因已经被很好地解释了。就第二个原因而言,请参考以下示例:
var MyClosureObject = (function (){
var MyName = 'Michael Jackson RIP';
return {
getMyName: function () { return MyName;},
setMyName: function (name) { MyName = name}
}
}());
注意 1:我们并没有将一个函数赋值给 MyClosureObject
,而且更重要的是,在最后一行调用该函数的结果。请注意最后一行的 ()
。
注意 2:还有一点需要了解的是,在 JavaScript 中,内部函数可以访问其所在函数的参数和变量。
让我们进行一些实验:
我可以使用 getMyName
得到 MyName
,它可以正常工作:
console.log(MyClosureObject.getMyName());
// Michael Jackson RIP
以下天真的方法不起作用:console.log(MyClosureObject.MyName);
// undefined
但我可以设置另一个名称并获得预期结果:
MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName());
// George Michael RIP
编辑:在上面的例子中,MyClosureObject
的设计是不需要使用 new
前缀的,因此按照惯例它不应该大写。
有没有一个参数,而“一堆代码”返回一个函数?
var a = function(x) { return function() { document.write(x); } }(something);
something
的值被分配给变量 a
所代表的函数。 something
的值可以是不同的(例如在循环中),并且每当 a
有一个新函数时,something
的值会随之改变。var x = something;
,而不是将 x
作为参数传递,因为这样更易读... - Christophx
并直接依赖于词法作用域,即document.write(something)
,则将使用新值... - Christophx
(作为参数或本地变量)。 - Christoph可能需要作用域隔离。这样,函数声明内部的变量不会污染外部命名空间。
当然,在现有的一半JS实现中,它们仍然会发生。
下面是一个实际例子,展示了自执行匿名函数的实用性。
for( var i = 0; i < 10; i++ ) {
setTimeout(function(){
console.log(i)
})
}
10, 10, 10, 10, 10...
for( var i = 0; i < 10; i++ ) {
(function(num){
setTimeout(function(){
console.log(num)
})
})(i)
}
0,1,2,3,4...
let
替代 var
,第一个情况就没问题了。 - Vitaly Zdanevich一个不同之处在于你在函数中声明的变量是局部的,所以当你退出函数时它们会消失,并且它们不会与其他代码中的变量发生冲突。