你不了解的JS笔记 - 函数作用域和块作用域

以下是读完《你不了解的JS》第一部分第三章后整理的笔记

函数中的作用域

函数作用域是指:属于这个函数的全部变量都可以在整个函数的范围内使用及复用(在嵌套的作用域中也可以使用)


隐藏内部实现

可以把变量和函数包裹在一个函数的作用域中,然后用这个作用域来隐藏它们

最小特权原则:应该最小限度的暴露必要内容,而将其他内容都隐藏起来,比如某个模块或对象的API设计

两个标识符可能具有相同的名字但用途却不一样,无意间可能造成命名冲突,冲突会导致变量的值被意外覆盖,隐藏作用域中的变量和函数可以避免同名标识符之间的冲突

当程序中加载了多个第三方库时,如果它们没有妥善的将内部私有的函数或变量隐藏起来,就会很容易引发冲突,这些库通常会在全局作用域中声明一个名字足够独特的变量,通常是一个对象,这个对象被用作库的命名空间,所有需要暴露给外界的功能都会成为这个对象的属性,而不是将自己的标识符暴露在顶级的词法作用域中

另外一种避免冲突的方法就是从众多模块管理器中挑选一个来使用,任何库都无需将标识符加入到全局作用域中,而是通过依赖管理器的机制将库的标识符显式的导入到另外一个特定的作用域中


函数作用域

区分函数声明和表达式最简单的方法是看function关键字出现在声明中的位置,如果function是声明中的第一个词,那就是一个函数声明,否则就是一个函数表达式

函数声明和函数表达式之间最重要的区别是它们的名称标识符将会绑定在何处,前者绑定在所在作用域中,后者绑定在函数表达式自身的函数中

函数表达式可以是匿名的,而函数声明则不可以省略函数名

匿名函数表达式缺点:

  • 匿名函数在栈追踪中不会显示出有意义的函数名,使得调试很困难
  • 如果没有函数名,当函数需要引用自身时只能使用已经过期的arguments.callee引用
  • 匿名函数省略了对于代码可读性/可理解性很重要的函数名,一个描述性的名称可以让代码不言自明

给函数表达式指定一个函数名可以有效解决以上问题,始终给函数表达式命名是一个最佳实践

IIFE:立即执行函数表达式,由于函数被包含在一对括号内部,因此成为了一个表达式,通过在末尾加上另外一个括号可以立即执行这个函数

常见用法:

  • 使用一个匿名函数表达式
  • 把它们当做函数调用并传递参数进去
  • 解决undefined标识符的默认值被错误覆盖导致的异常,将一个参数命名为undefined,但是在对应的位置不传入任何值,这样就保证在代码块中undefined标识符的值真的是undefined
  • 倒置代码的运行顺序,将需要运行的函数放在第二位,在IIFE执行之后当做参数传递进去

块作用域

变量的声明应该距离使用的地方越近越好,并最大限度的本地化

块作用域是一个用来对之前的最小授权原则进行扩展的工具,将代码从在函数中隐藏信息扩展为在块中隐藏信息

用with从对象中创建出的作用域仅在with声明中而从外部作用域中有效

try/catch的catch分句会创建一个块级作用域,其中声明的变量仅在catch内部有效

let关键字可以将变量绑定到所在的任意作用域中,为其声明的变量隐式地劫持了所在的块作用域

提升是指声明会被视为存在于其所出现的作用域的整个范围内,但是使用let进行的声明不会在块作用域中进行提升,声明的代码被运行之前,声明并不存在

P34最上方描述有错误,不应该是由于click函数形成闭包,而是因为var声明的是全局变量,导致生命周期很长

for循环头部的let不仅将i绑定到了for循环的块中,事实上,它将其重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值

const同样可以用来创建块作用域变量,但其值是固定的,之后任何视图修改值的操作都会引起错误

posted @ 2025-06-02 19:30  永生辉皇  阅读(8)  评论(0)    收藏  举报