函数中的做用域 es6
所谓函数做用域,就是属于这个函数的所有变量均可以在整个函数的范围内使用及复用。函数
1 function foo(a) { 2 var b=a; 3 function bar(c){ 4 var c=b*2; 5 console.log(c); 6 } 7 bar(); //4 8 } 9 foo(3);
1 function foo(a) { 2 var b=a; 3 function bar(c){ 4 var c=b*2; 5 console.log(c); 6 } 7 bar(); 8 } 9 bar(2); //not defined
命名冲突工具
在同一做用域中,相同的命名会引发冲突。spa
1 function foo() { 2 function bar(a){ 3 i=3; 4 console.log(i+a); 5 } 6 for(var i=0;i<10;i++){ 7 bar(i); 8 } 9 } 10 foo();
上面的代码将会引发冲突,函数会一直执行下去,行成死循环。code
如何避免命名冲突呢?对象
(1)全局命名空间blog
一些第三方库一般都是在全局对象中声明一个独特的对象,库的方法和实例都在这个对象中,当咱们调用时直接调用这个独特的对象就行了。作用域
1 var MyLibrary={ 2 param1:'param1', 3 doSomething:function () { 4 5 }, 6 doElseThing:function () { 7 8 } 9 //....... 10 }
(2)模块管理get
另外一种避免冲突的方法和如今的模块机制很接近,就是从众多模块管理器中挑选一个来使用。使用这些工具,任何库都无需将标识符加入到全局做用域中,而是经过依赖管理器的机制将库的标识符显示地导入到另外一个特定的做用域中it
立执行函数
将函数包裹在一对括号中,使之成为一个表达式,再在后面加一个括号,使之执行,这样函数就会自执行。这种模式又称IIFE。
自执行函数有两种写法形式,第一种是将整个函数写在括号中,再在括号外面加一对括号:(function(){//do something})();
还有一种是:(function(){//do something}())。
这两种写法功能都相同。
自执行函数传参
1 (function(doc){ 2 var a='按钮'; 3 doc.getElementById('btn').innerText=a; 4 })(document);
块做用域
当咱们写for循环时,咱们都但愿i只在循环的上下文中起到做用,而事实上i会被绑定到他所在的做用域中。好比上面的命名冲突中的例子。
那么如何解决块做用域的问题呢?
(1)使用自执行函数将循环包住,设置私有做用域。
1 function foo(a) { 2 function bar(a){ 3 i=3; 4 console.log(a+i); 5 } 6 (function(){ 7 for(var i=0;i<10;i++){ 8 bar(i); 9 } 10 })(); 11 } 12 foo(3); //3 4 5 6 7 8 9 10 11 12
(2)使用es6中的let
let关键字为其声明的变量隐式地劫持了所在的做用域,上述例子能够改为:
1 function foo(a) { 2 function bar(a){ 3 i=3; 4 console.log(a+i); 5 } 6 for(let i=0;i<10;i++){ 7 bar(i); 8 } 9 } 10 foo(3); //3 4 5 6 7 8 9 10 11 12
(3)es6中const也会建立块级做用域。
const能够建立块级做用域,可是他表示常量。修改const建立的变量的值会报错。
1 var foo=true; 2 3 if(foo){ 4 var a=2; 5 const b=3; 6 7 a=3;//正常 8 b=4;//错误 9 } 10 11 console.log(a); //3 12 console.log(b); //b is not defined