JavaScript函数作用域

2020-10-22  本文已影响0人  苹果王子刘泽庆

1.函数定义的本质是绑定

函数定义是一个常规的绑定,其中绑定的值是函数。
函数的参数表现得像常规绑定,但它们的初始值由函数的调用者给出,而不是函数本身的代码给出。

2.绑定和作用域

每个绑定都有一个作用域,它是程序中此绑定可见的一部分。

每次调用函数,都会创建函数内这些绑定的新实例。这在函数之间提供了一些隔离,即每个函数调用都在它自己的小世界(其局部环境)中运行,并且经常可以在不了解全局环境中发生的事情的情况下被理解。

注意事项

letconst声明的绑定,实际上是在声明它们的中局部可见,所以如果你在循环(块)中创建上面两种绑定中的一种,循环(块)之前和循环(块)之后的代码都无法“看到”这一绑定。

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终端下测试得到如下图所示结果:

image.png
在分支模块外输出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左边的那个键)。如果是普通单引号会发生如下错误。

image.png
在这个示例中,ingredient函数嵌套在hummus函数内部,因此在hummus函数作用域内部嵌套了ingredient函数的作用域。
ingredient函数内的代码可以看到外部函数hummus的factor绑定,但它的局部绑定(amount、unit、name)在外部函数hummus中则是不可见的。 image.png

词法作用域

块内可见的绑定集由程序文本中此块的位置确定。每个局部作用域可以查看包含它的所有局部作用域,并且所有作用域都可以看到全局作用域。这种绑定可见性的方法称为词法作用域。

上一篇下一篇

猜你喜欢

热点阅读