函数中的作用域:
属于这个函数的全部变量可以在整个函数的范围内使用以及复用(函数嵌套的作用域中也可以使用)
隐藏内部实现
代码片段+变量使用一个函数包装起来。实际上就是把这些函数里边的代码和变量隐藏起来了。
使用隐藏实现的原则
谁要使用这些函数或者变量,就把这些变量和函数放在谁的里边。
function doSomething(a) {
b=a+dosomethingElse(a*2);
console.log(b*3);
}
function dosomethingElse(a) {
return a-1;
}
var b=1;
doSomething(2); //15
上面的这个在功能上实现了,但是因为只有doSomething()这个函数用到了dosomethingElse()和b 其他函数都不会用到了这个两个变量,更合利的方式应该是将b和dosomethingElse()放在doSomething()内部,这样的做法更合理。
function doSomething(a) {
var b=1;
b=a+dosomethingElse(a*2);
console.log(b*3);
function dosomethingElse(a) {
return a-1;
}
}
doSomething(2); //15
这样b和dosomethingElse()就不会再被外部访问。体现的就是隐藏内部实现的原则。
设计API时使用隐藏内部实现的两个好处:
1、函数内部的这些被包装起来的bain两和函数不会被有意或者无意以非预期的方式使用
2、可以避免同名标识符之间的冲突。
设计API的时候使用隐藏内部实现的方法:
1、在全局作用域中申明一个名字足够独特的变量,然后第三方的所有的方法都会称为这个变量的属性
2、模块管理 所有的标识符都不能注入到共享域中,在保持私有、无冲突的作用域中,实现功能
函数作用域
任意代码片片段外部添加包装函数,可以将内部的变量和函数定义“隐藏”起来,外部作用域无法访问包装函数内部的任何内容。
var a=2;
function cc() {
var a=3;
console.log(a); //3
}
cc();
console.log(a); //2
匿名和具名
一个典型的匿名函数的应用
setTimeout(function () {
console.log(1);
},1000);
但是使用匿名函数有以下几个缺点:
1、匿名函数在追踪栈中不会显示有意义的函数名,使得调试很困难
2、如果没有函数名,当函数需要引用自身时只能使用已经过时的arguments.callee引用
setTimeout(function () {
console.log(1);
arguments.callee();
},1000);
上边这个程序是一个死循环,不可以随便运行。
3、函数省略了对于代码的可读性/可理解性很重要的函数名。函数名可以说明代码的功能。
setTimeout(function timeoutHander() {
console.log(1);
},1000);
这样写更方便阅读。
立即执行的函数表达式IIFE
var a=2;
(function IIFE(global) {
var a=3;
console.log(a);//3
console.log(global.a); //2
})(window);
使用立即执行函数表达式改变函数的执行顺序
var a=2;
(function IIFE(def) {
def(window);
console.log(1); //最后输出的1
})(function def(global) {
var a=3;
console.log(a); //3
console.log(global.a);//2
});
本来先写的console.log(1); 这句话,应该是先输出这句话,但是因为使用了立即执行的表达式所以将函数的执行的顺序弄反了,所以会先输出 2,3 再输出1
块作用域
js本身自己没有块级作用域
但是js中的for和if和with中的变量都会绑定到外部的作用域中。
if中的bar被绑定到了全局作用域中(if语句的当一层作用域中)
var foo=true;
if(foo){
var bar=3;
console.log(bar);
}
console.log(bar);
for中的ss被绑定到了全局作用域中(for的上一级作用域)
for(var i=0;i<5;i++){
var ss=i;
console.log(ss);
}
console.log(ss); //4
with中的a变量被绑定到了foo的上一级(全局)
function foo(obj) {
with (obj){
a=4;
}
}
var ob1={a:1};
var ob2={b:2};
foo(ob1);
foo(ob2);
console.log(ob1.a); //4
console.log(ob2.a); //undefined
console.log(a); //4
let关键字:将变量绑定到任意的作用域中 ES6
var foo=true;
if(foo){
let bar=2;
console.log(bar); // 2
}
console.log(bar); //Uncaught ReferenceError: bar is not defined
let和var的功能相同但是let可以将变量绑定到任意的作用域中。这时ES6提供一种除了var以为外的另一种定义变量的方式
const关键字 ES6
同样可以创建块级作用域变量,但是这个值是固定的以后任何程序的修改都会发生错误。
var foo=true;
if(foo){
var a=2;
const b=3;
a=3;
b=4; //错误,因为不允许任何的程序对它进行修改
}
console.log(a); //2
console.log(b); //Uncaught ReferenceError: b is not defined
ES6中的关键字const可以创建块级作用域。