JavaScript函数作用域
2020-10-22 本文已影响0人
苹果王子刘泽庆
1.函数定义的本质是绑定
函数定义是一个常规的绑定,其中绑定的值是函数。
函数的参数表现得像常规绑定,但它们的初始值由函数的调用者
给出,而不是函数本身的代码给出。
2.绑定和作用域
每个绑定都有一个作用域
,它是程序中此绑定可见的一部分。
-
全局绑定: 对于在任何函数或块之外定义的绑定,作用域是整个程序,这意味着你可以在任何地方引用此类绑定。
-
局部绑定:对于在函数内部创建的作为函数参数的绑定 或 在函数内部声明的绑定只能在此函数内引用。
每次调用函数,都会创建函数内这些绑定的新实例。这在函数之间提供了一些隔离,即每个函数调用都在它自己的小世界(其局部环境)中运行,并且经常可以在不了解全局环境中发生的事情的情况下被理解。
注意事项
用let
和const
声明的绑定,实际上是在声明它们的块
中局部可见,所以如果你在循环(块)中创建上面两种绑定中的一种,循环(块)之前和循环(块)之后的代码都无法“看到”这一绑定。
2015年之前的JavaScript中,只有函数才能创建新的作用域,因此使用
var
关键字创建的旧式绑定在其出现的整个函数内是可见的,如果它们不在一个函数中,则它们在全局作用域内可见。
let x = 10;
if (true){
let y = 20;
var z =30;
console.log(x + y + z); //输出60
}
console.log(x + z); //输入40
console.log(x + y + z); //报错,因为y定义在分支流程模块内,模块外不可见
在node.js终端下测试得到如下图所示结果:
在分支模块外输出
x+y+z
时,报出了ReferenceError: y is not defined(引用错误:y未定义)。这是因为使用let定义的y变量只在其声明的块内可见(此处为if模块的大括号内)。因此无法在块外引用。
嵌套作用域
JavaScript不仅区分全局绑定
和局部绑定
。它还可以在其他块和函数内创建块和函数,从而产生更多的局部作用域。
如下:
const hummus = function (factor) {
const ingredient = function (amount, unit, name) {
let ingredientAmount = amount * factor;
if (ingredientAmount > 1) {
unit += "s"; //如果剂量大于1,则输出unit时末尾增加s,变为units(复数)
}
console.log(`${ingredientAmount} ${unit} ${name}`); //注意:此处用的是反单引号
};
ingredient(1, "can", "chickpeas");
ingredient(0.25, "cup", "tahini");
ingredient(0.25, "cup", "lemon juice");
ingredient(1, "clove", "garlic");
ingredient(2, "tablespoon", "olive oil");
ingredient(0.5, "teaspoon", "cumin");
};
node.js中测试结果为:
image.png
注意:在此例子中,console.log(${ingredientAmount} ${unit} ${name}
); 中使用的是反单引号(主键区左上角数字键1左边的那个键)。如果是普通单引号会发生如下错误。
在这个示例中,ingredient函数嵌套在hummus函数内部,因此在hummus函数作用域内部嵌套了ingredient函数的作用域。
ingredient函数内的代码可以看到外部函数hummus的factor绑定,但它的局部绑定(amount、unit、name)在外部函数hummus中则是不可见的。 image.png
词法作用域
块内可见的绑定集由程序文本中此块的位置确定。每个局部作用域可以查看包含它的所有局部作用域,并且所有作用域都可以看到全局作用域。这种绑定可见性的方法称为词法作用域。