const在函数参数表中的作用_ES6函数默认参数及作用域详解

本文详细探讨了ES6中函数默认参数的使用和作用域特性,包括ES5函数参数的问题、ES6中函数默认参数的注意事项、默认参数的作用域以及不同浏览器对于重复声明的处理差异。总结了ES6函数作用域的两个独立部分:函数参数作用域和函数体作用域,并强调了函数参数默认值的惰性求值特点。
摘要由CSDN通过智能技术生成

函数默认参数及作用域详解

ES6引入了函数默认参数,先来看下例中对比

//es5
function fn(x,y){
    if(typeof y === 'undefined'){
        y = 'world';
    }
    console.log(x,y);
}
fn('hello');//hello world
//------------------------------------
//es6
function fn(x,y='world'){
    console.log(x,y);
}
fn('hello');//hello world

通过上例可以看出 默认参数这一功能大大的让代码变得简洁而自然,一目了然。下面回顾一下es5中函数参数相关内容

ES5中函数参数及覆盖问题

es5中函数内部作用域是包括: 函数参数变量 函数体内声明的变量 this arguments 下面回顾一下函数参数被覆盖问题的一个例子

function test(a,b){
    console.log(a);
    function a(){}
    var b = 10;
    console.log(b);
}
test(22,33);

函数内重复声明变量为函数模式(上例的function a(){})时会覆盖掉函数调用时传递过来的实际参数 a,这就说明实际参数赋值给形式参数 是在函数内部的函数声明提升之前,最终导致 函数声明提升 覆盖掉了 a=22的实参向形参赋值的操作
函数内重复声明变量为var形式声明是 变量提升 相当于在开头只声明变量并不赋值var b; 这种单纯的声明变量不赋值并不会影响变量原来的初始化值 此时变量b的值还是 33;等到执行 b=10的时候才会改变变量b的值

ES6中函数默认参数注意点

使用参数默认值是和不使用参数默认值的处理逻辑有很大区别 * 参数不能重复

function bar(x=10,x,y){
    console.log(x,y);
}
//Uncaught SyntaxError: Duplicate parameter name not allowed in this context
  • 参数变量默认会声明,类似使用let(作者猜测,哈哈) 函数体内不能再用 let 或者 const 再次声明
function bar(x=10,y){
    let x=2;//error
}
//Uncaught SyntaxError: Identifier 'x' has already been declared
  • 函数默认参数的值是在使用时进行求值,而不是声明时求值,也就是说,参数默认值是惰性求值
//摘自阮一峰ES6入门教程
let x = 99;
function foo(p = x + 1) {
    console.log(p);
}
foo() // 100
x = 100;
foo() // 101

函数默认参数作用域

我们都知道ES5函数参数只用Local Scope作用域;而ES6中函数默认值参数会形成单独的作用域,这个作用域占用了之前的Local Scope 而函数体内声明的变量形成了一个块级作用域Block Scope

66028767eed03dbd7af8c45973af71f3.png


图中断点停留在了 var name = 'zhangsan'处,右边的作用域(Scope)中显示了三个作用域环境 分别是Block,Local,Global。块级作用域Block中是函数体内声明的变量作用域,Local作用域中显示的是函数参数所在的作用域环境。Global表示全局作用域。
块作用域Block中存在声明提升所以显示的值都为undefined,只有当执行到变量赋值时才会被赋予真是的值。这跟之前声明提升(变量声明和函数声明)的逻辑是一致的。

如果声明函数呢?请看下图(chrome 浏览器)

017d355617847262cf5c1f75d003636c.png

火狐浏览器

b3a9a34d4ba8480d4337d9a2203b9ca4.png

通过两图对比可以发现 chrome浏览器中函数的声明不会显示到Block Scope中 而 火狐浏览器会正常显示,那样我们猜测 只声明变量 不初始化赋值 会不会也有这种情况

chrome 浏览器

a9e8ec705a27ae98effd60701ffdfd22.png

火狐浏览器

409d2ab5d11db61acfa3c2be76212557.png

从图中对比发现 确实是chrome 浏览器变量只声明不赋值和函数声明确实不出现在块级Block作用域中,而火狐浏览器表现正常

这难道是在chrome 浏览器中声明不生效吗?那我们打印一下这些变量看看到底有没有。

chrome浏览器

8db4eeeee5c4adfbe44d3030dac21675.png

火狐浏览器

31568726bf02f34b2ee6a4453c6989fb.png

打印变量都会显示到块级Block作用域中。以下是作者个人猜测:

chrome浏览器,只有声明的变量和函数在该作用域内被调用或者引用的时候才会显示(可能这是chrome浏览器的一种优化方案,用到的时候才会显示,不用就不会显示),然而在 火狐浏览器中只要声明就会一直显示

通过上面的介绍我们都知道函数参数和函数体内会形成两个独立的作用域 函数参数作用域对应于Local Scope
函数体内作用域对应于Block Scope

如果在函数体内重复声明参数对应的变量浏览器会怎么处理(这里只能使用var 声明,不能使用 letconst 否则会报错)

函数默认参数重复声明

我们先看看截图上的信息 * 被覆盖的参数声明为变量(var形式)时

bc1cdc02b270eeb3d8d4e51b545c663d.png

火狐浏览器与chrome浏览器表现行为一致就不贴火狐浏览器的截图了 可以看到只要函数体内声明的变量跟函数参数重复时 就会把参数作用域(Local Scope)内对应的变量的值直接赋值给了函数体内对应的变量。这看起来就好比 从函数参数作用域中拷贝了一份变量 到 函数体内,嗯 我们可以这么理解(至少作者是这么理解的,不具有权威性)之后再函数体内对重复的变量进行操作 都只是函数体内的Block Scope作用域内的变量改变,不会影响到函数参数作用域相同变量名的改变,如果想改变可以通过函数默认参数设置为一个函数。

function foo(m='local',n=function(){
    console.log(m);//-----2
    m='change';
    console.log(m);//-----3
}){
    var m = 'block';
    console.log(m); //-----1
    n();
    console.log(m);//-----4
}

foo();// block   local  change   block;

函数执行之前作用域变量分布

e714bd88ea6ed3f8f80ee8b63562a780.png

执行 var m='block' 的时候是对块级作用域 Block Scope 内的 m 进行重新赋值,并不影响 函数参数作用域 Local Scope 中变量 m 的值,之后又执行 n() ,n函数内的 m 由于没有使用 var 声明所以直接找到的是 Local Scope 中的 m 后面的赋值是针对 函数参数作用域内的 m 进行赋值 之后又打印了 这个 m (参数作用域内的m) 函数 n() 执行完毕之后 回到 函数体内 接着打印 m 这里的 m 表示的还是函数体作用域( Block Scope )中的 m 函数 n() 的执行并不会影响函数体内的 m 变化;

  • 被覆盖的参数声明为函数时
    先看一个不重复声明的情况

dc8c58da5ec8f51cc9f3abea5df00837.png

这样 function n(){} 直接在块级作用域Block Scope内部提升到最前方,打印结果为一个函数
如果存在var重复声明呢?

afda4fe750b04aea1e4b38d323394a04.png

从图上可以看出 这里的function n(){} 重复声明没有起到作用,感觉好想是被覆盖掉了。
我们看看火狐浏览器的截图

b7eebbb6b8060dfd0f3012ebae4c0780.png

火狐浏览器能够显示出来 这就存在兼容性问题了
chrome 浏览器和 火狐浏览器的 处理顺序不一致,以下内容为作用推测没有实质性深入验证: chrome 浏览器 重复变量声明时会赋值一份函数参数作用域内的变量及初始值,这个复制的时机在该函数体内函数声明提升之后,就会造成 函数声明会被初始化为函数参数作用域内的变量值 覆盖掉。

而火狐浏览器是 恰好相反,函数声明提升在 变量被赋值为函数参数作用域相同变量的值之后,这样就能得到上图的允许结果。

总结

通过深入介绍我们大致明白了

  • ES5函数内只有一个Local Scope作用域
  • ES6带默认参数的函数作用域分为2个:函数参数作用域Local Scope 和 函数体作用域Block Scope 这两个作用域是相互独立的
  • 具有默认值参数的函数参数不能重复声明
  • 具有默认参数的函数体内不能再次使用let const等声明参数变量
  • 函数参数默认值是惰性求值的
  • 函数体内重复声明的变量的初始值会是函数参数作用域内具有相同变量名的值,再从新声明成函数是 chrome 和 火狐浏览器处理变量逻辑不一样最终得到的结果也不一样(一般我们不这么玩,只是深入明白处理机制)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值