一、理解作用域
作用域负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套严格的规则,确定当前执行的代码对这些标识符的访问权限。
二、词法作用域
词法作用域是由你在写代码时将变量和块作用域写在哪里决定的。
2.1 欺骗词法
2.1.1 eval
严格模式下,则无法修改所在的作用域
function foo(str,a){
eval(str) //欺骗,eval调用var b = 3 ,b相当于在foo内部创建新变量,并且遮蔽了b=2这个变量
console.log(a,b); //1,3
}
var b = 2
foo("var b = 3", 1)
2.1.2 with
with通常被当作重复引用同一个对象的多个属性快捷方式,不需重复引用对象本身。
三、函数作用域
属于这个函数作用域的全部变量可以在整个函数范围内使用及复用。
function foo(a){
b = a + c(a * 2)
console.log(b * 3);
}
function c(a){
return a - 1
}
var b
foo(2) //15
console.log(b); //此时b全局都能访问到,应该放到foo()里才最安全
函数若不想显示调用,要自动运行
四、块作用域
五、提升
函数作用域和块作用域的行为是一样的,可以总结为:任何声明在某个作用域内的变量,都将附属于这个作用域。
var a = 2,JavaScript 实际上会将其看成两个声明:var a; 和 a = 2;。第一个定义声明是在编译阶段进行的。第二个赋值声明会被留在原地等待执行阶段。
只有函数声明本身会被提升,而赋值或其他运行逻辑会留在原地。
foo() //函数声明提升
function foo(){
console.log(a); //undefined 变量声明提升
var a = 2;
}
函数表达式却不会被提升。
foo() //提升
var foo = function bar(){
console.log(a); // foo is not a function
var a = 2;
}
5.1函数优先
函数会首先被提升,然后才是变量。 看函数在哪里调用
foo()
var foo
function foo(){
console.log(1); //第2个出现 1
}
foo = function(){
console.log(2); //foo is not a function
}
function foo(){
console.log(3); //第1个出现 3
}
var foo
function foo(){
console.log(1); //第3个出现 1
}
foo = function(){
console.log(2); //第1个出现 2
}
function foo(){
console.log(3); //第2个出现 3
}
foo()
六、作用域闭包
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
好处
解决循环时
var buttons = document.querySelectorAll("button")
for (var i = 0; i < buttons.length; i++) {
this.buttons[i].index = i //把i值赋值给index
buttons[i].onclick = function(){
console.log(this.index); //0 1 2
}
}
这种会创建更多的构造函数
var buttons = document.querySelectorAll("button")
for (var i = 0; i < buttons.length; i++) {
(function(i){ //调用三次fn
buttons[i].onclick = function(){
console.log(i); //0 1 2
}
})(i) //把外面的i传递给function里
}