JavaScript暂时性死区以及函数作用域

 更新时间:2023年07月19日 10:29:48   作者:DCodes  
这篇文章主要为大家介绍了JavaScript暂时性死区以及函数作用域示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

暂时性死区

暂时性死区也就是变量声明到声明完成的区块,这个区块是一个封闭的作用域,直到声明完成。
如果在变量声明之前使用该变量,那么该变量是不可用的,也就被称为暂时性死区。

  • var 没有暂时性死区,因为var存在变量提升
  • let、const有块级作用域,没有变量提升,存在暂时性死区
console.log(a); // 报错 Cannot access 'a' before initialization
let a = '东方不败'
console.log(b); // 报错 Cannot access 'b' before initialization
const b = '东方不败'
console.log(c);   // undefined 因为var存在变量提升
var c = '东方求败'

ES6规定,如果代码块中存在letconst命令声明的变量,这个区块对这些变量从一开始就形成了封闭作用域,直到声明语句完成,这些变量才能被访问(获取或设置),否则会报错ReferenceError。这在语法上称为“暂时性死区”(英temporal dead zone,简 TDZ),既代码块开始到变量生命语句完成之前的区域。

函数作用域

案例一

一旦设置了参数的默认值,函数进行生命初始化时,参数就会形成一个单独的作用域,等初始化结束,这个作用域就会消失,这种语法在不设置参数默认值时不会出现。

var x = 1
function f(x,y = x){
     console.log(y);
    }
f(2)  // 2

上面这个例子中,函数参数这里(x,y = x),这个区域就是单独的作用域,y默认的x变量指向第一个参数x,而不是全局变量x,这里调用f函数,向x传递数值2y = x 那么 y = 2,打印结果为2

案例二

let x2 = 1
function f2(y2 = x2){
         let x2 = 2
         console.log(y2);
     }
f2()  // 1

调用f2函数,由于未给f2函数任何参数,并且 y2 = x2 形成一个单独的作用域,在这个作用域里x2并未定义,所以x2指向的是外层全局变量x2y2 = x2 也就是y2 = 1,在这里,函数内部的x2并未起到任何作用。

函数执行的时候会先执行参数,再执行函数体。

// 报错
function f2(y2 = x2){
         let x2 = 2
         console.log(y2);
     }
f2()  // 报错

上面的例子中,如果去掉全局变量x2则会报错,因为变量未声明,给y2赋值了一个未声明的变量,报错。

var xx = 1
function fxx(xx = xx){
    console.log(xx);
    }
fxx()

上面这个写法也会报错,由于函数的参数存在单独的作用域,在这个参数作用域内,执行结果为 let xx = xx,给xx赋值一个未声明的变量xx报错。(暂时性死区)

如果函数的默认参数是函数,该函数的作用域也要遵循这个规则。

let foo = 'out'
function bar(func = () => foo){
      let foo = 'come'
      console.log(func());
  }
bar()  // out

这个例子中,函数的参数是func默认值是一个匿名函数,返回值为变量foo,由于函数参数这里形成一个单独的作用域,在这个作用域里面并没有定义变量foo,所以foo会指向外层全局变量foo。如果去掉全局变量foo='out'报错,赋值了一个未声明的变量。

应用可以利用这个特性写一个参数默认值错误抛出,如果参数并未传参则抛出一个错误。

function throwErr(){
    throw new Error('参数不得省略')
    }
    
function omits(mustfn = throwErr()){
    return mustfn
    }
omits(); // 未传参抛出错误 : 参数不得省略

调用omits函数未传参数,该函数就会默认调用throwErr()函数并抛出错误。

如果将参数默认值设置为 undefined 则表示该参数是可以省略的。

rest参数

arguments

arguments可以获得函数的参数值以及函数信息(name、length)等

function au(arr){
        console.log('arguments:',arguments);
    }
    au(2,1,4,3)

可以通过数组方法对函数参数进行操作,例如排序。

arguments对象不是数组,而是一个类似数组的对象,为了使用数组的方法,必须使用Array.from先将其转为数组。

function au(arr){
     // 通过数组方法对函数参数进行排序
     return Array.from(arguments).sort();
   }
console.log(au(2,1,4,3))  // [1,2,3,4]

rest参数ES6提供了rest参数,语法:(...变量名),其实就是剩余运算符,通过rest参数就可以很容易的对函数参数进行操作,并且

rest的参数是一个真正的数组。

// resy参数(剩余运算符)
function residue(...val){
      console.log(val);  // [1,2,3]
    }
residue(1,2,3)

rest参数(剩余运算符)只能放到最后一位,否则报错

// function residue2(...val,b){}  // 剩余运算符不是最后一位,报错
function residue3(c,...val){
  console.log(c,val);  // 1 [2,3,4,5] 
 }
residue3(1,2,3,4,5)

上面arguments完成的参数排序,使用rest可以很轻松的做到,并且语义更强,更方便阅读。

let au2 = (...val) => val.sort()
console.log(au2(2,1,4,3));  // [1, 2, 3, 4]

严格模式

ES5开始,函数内部可以设定为严格模式: function s(){ 'use strict'// 严格模式 }

// es5严格模式
function s(){
   'use strict'   // 严格模式
   // 代码.....
}

ES6做了修改,规定只要函数参数使用了默认值、解构赋值、扩展运算符,那么函数内部就不能显示设定为严格模式,否则报错。

// es6严格模式  报错,因为设置了函数默认值
function s2(a,b = a){
   'use strict'
   // 代码.....
}
// 报错,使用了解构赋值
const s3 = function({a,b}){
    'use strict'
}
// 报错,使用了剩余运算符
const s4 = (...a) => {
    'use strict'
}

es6这样设置的原因是,函数内部的严格模式应该同样适用于函数体和函数参数,但是,函数执行的时候会先执行参数,再执行函数体,这样就有一些不严谨的情况,只有函数体中才能知道参数是否应该以严格模式执行,但是函数的参数确是先执行,所以es6修改了函数参数关于严格模式的行为。

function s5(val = 070){
    'use strict'
    return val
}
s5()  // 报错

这一段,函数的默认值是八进制070,严格模式下不能使用前缀0表示八进制,所以报错。
但实际上是因为函数设置了默认参数的原因,函数先执行参数,再进函数体,由于es6限制,报错。

有两种方法可以规避这种限制

第一种:设置全局严格模式

'use strict'
function s6(val = 100){
  console.log(val);
}
s6()  // 100

第二种方法:把函数嵌套在一个无参数的立即执行函数里

const s7 = () => {
     'use strict'
     let a;
     return (function(val = 200){ return val })()
}
console.log(s7());

匿名函数的调用方法:在上述例子(function(val = 200){return val})()中,将整个return的函数用()套起来,尾部加一个()调用即可,()在函数中代表调用。

案例源码:https://gitee.com/wang_fan_w/es6-science-institute

以上就是JavaScript暂时性死区以及函数作用域的详细内容,更多关于JS暂时性死区函数作用域的资料请关注脚本之家其它相关文章!

相关文章

  • javascript+jQuery实现360开机时间显示效果

    javascript+jQuery实现360开机时间显示效果

    这篇文章主要介绍了javascript+jQuery实现360开机时间显示效果,在文中给大家提到了js实现时间倒计时的代码,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-11-11
  • uniapp小程序底部tabbar图标大小设置办法

    uniapp小程序底部tabbar图标大小设置办法

    这篇文章主要给大家介绍了关于uniapp小程序底部tabbar图标大小设置办法的相关资料,在使用uniapp进行开发时,tabbar是我们使用的很频繁的一个组件,但是在特定的平台会有一些使用上的限制,需要的朋友可以参考下
    2023-08-08
  • 火狐textarea输入法的bug的触发及解决

    火狐textarea输入法的bug的触发及解决

    在firefox中,如果一个textarea获取焦点,在输入法激活的状态如果这时js将该textarea的value修改,那么该textarea会直接被清空,下面是具体的解决方法,遇到类似问题的朋友可以参考下
    2013-07-07
  • JS获取子窗口中返回的数据实现方法

    JS获取子窗口中返回的数据实现方法

    下面小编就为大家带来一篇JS获取子窗口中返回的数据实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-05-05
  • Windows下支持自动更新的Electron应用脚手架的方法

    Windows下支持自动更新的Electron应用脚手架的方法

    这篇文章主要介绍了Windows下支持自动更新的Electron应用脚手架的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • 深入了解JavaScript中逻辑赋值运算符的应用

    深入了解JavaScript中逻辑赋值运算符的应用

    逻辑赋值是对现有数学和二进制逻辑运算符的扩展。我们先复习一下,然后看看把它们结合在一起能得到什么,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-11-11
  • js canvas实现擦除效果示例代码

    js canvas实现擦除效果示例代码

    擦除效果在我们日常开发中也是时有见到的,通过擦除效果大大加强了与用户的交互性,所以下面这篇文章主要给大家介绍了利用js和canvas实现擦除效果的相关资料,文中给出了详细的介绍和示例代码,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-04-04
  • Javascript调试之console对象——你不知道的一些小技巧

    Javascript调试之console对象——你不知道的一些小技巧

    这篇文章主要总结了console对象的一些有用的方法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-07-07
  • javascript中的隐式调用

    javascript中的隐式调用

    本篇文章给大家详细介绍了javascript中的隐式调用相关知识点,对此有兴趣的可以跟着小编一起学习下。
    2018-02-02
  • Object.keys方法实例详解

    Object.keys方法实例详解

    这篇文章主要介绍了Object.keys方法实例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-09-09

最新评论