javascript中的作用域(二)

169 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

前言

大家好呀,我是L同学。在上篇文章javascript中的作用域中,我们学习了javascript中的作用域,包括局部作用域、全局作用域、作用域链等知识。今天,在这篇文章中,我们继续学习闭包、变量提升和函数等相关知识点。

闭包

闭包让你可以在一个内层函数中访问到其外层函数的作用域的数据。闭包是一种比较特殊的函数,使用闭包能够访问函数作用域中的变量。从代码形式上看闭包是一个做为返回值的函数。闭包本质上仍是函数,只不过不是从函数内部返回的。闭包能够创建外部可访问的隔离作用域,避免全局变量污染。过度使用闭包可能造成内存泄漏。需要注意的是,回调函数也能访问函数内部的局部变量。

<script>
  function foo() {
    let i = 0;

    // 函数内部分函数
    function bar() {
			console.log(++i);
    }

    // 将函数做为返回值
    return bar;
  }
  
  // fn 即为闭包函数
  let fn = foo();
  
  fn(); // 1
</script>

变量提升(预解析)

变量提升是 JavaScript 中比较“奇怪”的现象,它允许在变量声明之前即被访问。变量在未声明即被访问时会报语法错误,变量在声明之前即被访问,变量的值为 undefinedlet 声明的变量不存在变量提升,所以推荐使用 let。变量提升出现在相同作用域当中,那么我们在实际开发中推荐先声明再访问变量。

<script>
  // 访问变量 str
  console.log(str + 'world!'); //undefinedworld

  // 声明变量 str
  var str = 'hello ';
</script>

const

const是在es6中新增的一种定义变量的方式(常量的定义)。

  • 使用const声明的常量,不允许重新赋值。
  • 使用const声明的常量,必须有初始值。
  • const也没有预解析。
  • 使用const 声明的常量也会与{}进行绑定,形成块级作用域。
      //------ 使用const声明的常量,不允许重新赋值-------
      const a = 0
      a = 9
      console.log(a) //报错
      //------ 使用const声明的常量,必须有初始值----------
      const age
      console.log(age) // 报错
      //------ const也没有预解析----------
      console.log(address)
      const address = '上海'
      //------ 使用const 声明的常量也会与{}进行绑定,形成块级作用域----------
      if (true) {
        const tel = 123456789
      }
      console.log(tel)

let const var对比

let 和 var 和 const 的区别:

  1. let 必须先初始化变量,再使用变量,没有预解析的过程,let会与{}绑定,形成块级作用域
  2. var 会有预解析的过程,提升变量声明,不提升变量赋值
  3. const 是在es6中新增的一种定义变量的方式(常量的定义)
    • 使用const声明的常量,不允许重新赋值
    • 使用const声明的常量,必须有初始值
    • const也没有预解析
    • 使用const 声明的常量也会与{}进行绑定,形成块级作用域

函数

函数提升

函数提升与变量提升比较类似,是指函数在声明之前即可被调用。函数提升能够使函数的声明调用更灵活。函数表达式提升的是变量的声明,函数提升出现在相同作用域当中。

<script>
  // 调用函数
  foo();

  // 声明函数
  function foo() {
    console.log('声明之前即被调用...');
  }

  // 不存在提升现象
  bar();
  var bar = function () {
    console.log('函数表达式不存在提升现象...');
  }
</script>

函数参数默认值

声明函数时可以为形参赋值即为参数的默认值。如果参数未自定义默认值时,参数的默认值为 undefined。调用函数时没有传入对应实参时,参数的默认值被当做实参传入。

<script>
  // 设置参数默认值
  function sayHi(name="小明", age=18) {
    document.write(`<p>大家好,我叫${name},我今年${age}岁了。</p>`);
  }
  // 调用函数
  sayHi();
  sayHi('小红');
  sayHi('小刚', 21);
</script>

函数动态参数

arguments 是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参。 arguments的作用是动态获取函数的实参。需要注意的是,arguments是一个伪数组

<script>
  // 求和函数,计算所有参数的和
  function sum() {
    // console.log(arguments);
    let s = 0;
    for(let i = 0; i < arguments.length; i++) {
      s += arguments[i];
    }
    console.log(s);
  }

  // 调用求和函数
  sum(5, 10); // 两个参数
  sum(1, 2, 4); // 三个参数
</script>

剩余参数

我们可以借助 ... 获取函数的剩余实参。... 是语法符号,它放在最末函数形参之前,用于获取多余的实参。

<script>
  function config(baseURL, ...other) {
    console.log(baseURL);
    // other 是真数组,动态获取实参
    console.log(other);
  }

  // 调用函数
  config('http://baidu.com', 'get', 'json');
</script>