ECMAScript函数(一)

本文详细介绍了ES6中函数默认参数的特性,包括如何设置默认值,如何处理可选参数,以及默认参数如何影响arguments对象。在ES6中,函数参数可以有默认值,这使得代码更易读,同时也改变了arguments对象的行为。此外,还讨论了临时死区(TDZ)的概念,强调了默认参数值在函数调用时求值,以及不能访问未初始化的参数。
摘要由CSDN通过智能技术生成

函数是所有编程语言的最重要的组成部分,ES6的出现大力度的更新了函数的特性,在ES5的基础上进行了许多改进,让JavaScript编程更少出错,更加灵活。

  • ECMAScript5默认参数

function makeRequest(url, timeout, callback) {    timeout = timeout || 6000;    callback = callback || function () {    }    // 其他函数执行功能  }

       在本示例中,timeout和callback为可选参数, 如果不传入参数系统会赋一个默认值。对于函数的命名参数,如果不显式传值,则会默认为undefined。但是如果我们

      给第二个形参timeout传入值 0 ,也会被视为一个假值,并最终将timeout赋值为6000。

  这种情况下,需要通过typeof检查参数类型:

function makeRequest(url, timeout, callback) {        timeout = (typeof timeout != 'undefined') ? timeout : 6000;        callback = (typeof callback != 'undefined') ? callback : function () {
        };    // 其他函数执行功能  }
  • ECMAScript6中的默认参数值

  ES6简化了为形参提供默认值的过程,如果没有传入值则为其提供一个默认值:

function makeRequest(url, timeout = 6000, callback = function () {}) {    // 其他函数执行功能  }

上述示例中只有第一个参数是需要为其传值的,其他两个参数都有默认值。

  如果调用makeRequest()方法传入3个参数,则不使用默认值

// 使用timeout 和 callback的默认值  makeRequest("/ES6");
  // 使用callback的默认值  makeRequest("/ES6", 666);
  // 不使用默认值  makeRequest("/ES6", 666,function (ar) {      doSomething(ar);  })

按照ES6的语法,上述三次调用都传入了“/ES6”, 其余两个有默认参数的都是可选参数。  声明函数时,可以为任意参数指定默认值,在已指定默认值的参数后可以继续声明无默认值参数

 

function makeReques(url, timeout = 6000, callback) {
  }

只有当不为第二个参数传入值或者主动为第二个参数传入undefined时才会使用timeout的默认值:

  // 使用timeout的默认值  makeRequest("/ES6", undefined, function (ar) {
  })  // 使用timeout的默认值  makeRequest("/ES6");
  // 不使用timeout的默认值  makeRequest("/ES6", null, function (ar) {
  })

第三次调用函数时,不使用timeout的默认值,其值最终为null

 

  •  默认参数值对arguments对象的影响

function mixArgs(first, second) {      console.log(first === arguments[0]);      console.log(second === arguments[1]);      first = "c";      second = "d";    console.log(first === arguments[0]);    console.log(second === arguments[1]);  }  mixArgs("a", "b");

输出如下:

​​​​​​​

  true  true  true  true

 

在非严格模式下,命名参数的变化会同步更新到arguments对象中,所以当first和second被赋予新值时,arguments[0]和arguments[1]相应地也就更新了,最终所有===全等比较的结果为true。

然而,在ECMAScript 5的严格模式下,取消了arguments对象的这个令人感到困惑的行为,无论参数如何变化,arguments对象不再随之改变。依然是mixArgs()函数,我们将其设置为严格模式:

​​​​​​​

function mixArgs(first, second) {      "use strict";    console.log(first === arguments[0]);    console.log(second === arguments[1]);    first = "c";    second = "d";    console.log(first === arguments[0]);    console.log(second === arguments[1]);  }  mixArgs("a", "b")

再次调用mixArgs()方法,输出以下内容

  true  true  false  false

    此次调用改变first和second的值不会导致arguments改变,  在ECMAScript 6中,如果一个函数使用了默认参数值,则无论是否显式定义了严格模式,arguments对象的行为都将与ECMAScript 5严格模式下保持一致。

      默认参数值的存在使得arguments对象保持与命名参数分离,这个微妙的细节将影响你使用arguments对象的方式,

// 非严格模式  function mixArgs(first, second="b") {      console.log(arguments.length);    console.log(first === arguments[0]);    console.log(second === arguments[1]);    first = "c";    second = "d";    console.log(first === arguments[0]);    console.log(second === arguments[1]);  }  mixArgs("a");

这段代码会输出以下内容

  1  true  false  false  false
  • 默认参数表达式

可用通过函数执行来得到默认参数的值

function getValue() {    return 666;  }  function add(first, second = getValue()) {    return first + second;  }  console.log(add(1,1));    // 结果为 2  console.log(add(1));    // 结果为6

值得注意的是,首次解析函数声明时不会调用getValue()方法,只有当调用add()函数且不传入第二个参数时才会调用。我们稍微改动一下getValue()函数,  让它每次返回不同的值

 let value = 5;  function getValue() {      return value++;  }  function add(first, second = getValue()) {      return first + second;  }  console.log(add(1,1)) // 结果为2  console.log(add(1)) // 结果为6  console.log(add(1)) // 结果为7

        变量value的初始值为5,每次调用getValue()时加1。第一次调用add(1)返回6,第二次调用add(1)返回7,因为变量value已经被加了1。

  因为只要调用add()函数就有可能求second的默认值,所以任何时候都可以改变那个值。

 

  注意,当使用函数调用结果作为默认参数值时,如果忘记写小括号,例如,second= getValue,  则最终传入的是对函数的引用,而不是函数调用的结果。

 

  正因为默认参数是在函数调用时求值,所以可以使用先定义的参数作为后定义参数的默认值:

function add(first, second = first) {      return first + second;    }  console.log(add(1,1)) // 结果为2  console.log(add(1)) // 结果为2  

参数second的默认值为参数first的值,如果只传入一个参数,则两个参数的值相同,从而add(1, 1)返回2,  add(1)也返回2。可以将参数first传入一个函数来获得参数second的值

function getValue(value) {      return value + 5;  }  function add(first, second = getValue(first)) {    return first + second;  }  console.log(add(1,1)) // 结果为2  console.log(add(1)) // 结果为7示例中,声明second = getValue(first),所以尽管add(1, 1)仍然返回2,但是add(1)返回的是(1+6)也就是7。

  在引用参数默认值的时候,只允许引用前面参数的值,即先定义的参数不能访问后定义的参数

 

function add(first = second, second) {    return first + second;  }  console.log(add(1,1)) // 结果为2  console.log(add(undefined, 1)) // 错误

调用add(undefined, 1)会抛出错误,因为second比first晚定义,因此其不能作为first的默认值。这就涉及到临时死区(TDZ) 的原理。

  •   默认参数的临时死区

 

      与let声明类似,定义参数时会为每个参数创建一个新的标识符绑定,该绑定在初始化之前不可被引用,如果试图访问会导致程序抛出错误。  当调用函数时,会通过传入的值或参数的默认值初始化该参数。

function getValue(value) {    return value + 5;  }  function add(first, second = getValue(first)) {    return first + second;  }  console.log(add(1,1)) // 结果为2  console.log(add(1)) // 结果为7

调用add(1, 1)和调用add(1)实际上相当于执行以下代码来创建first和second参数值:

// 表示调用add(1,1)的javaScript代码  let first = 1;  let second = 1;
  // 表示调用add(1)的JavaScript代码  let first = 1;  let second = getValue(first);

初次执行函数add()时,绑定first和second被添加到一个专属于函数参数的临时死区(与let的行为类似)。

      由于初始化second时first已经被初始化,所以它可以访问first的值,但是反过来就错了。

// 表示调用add(1,1)的javaScript代码  let first = 1;  let second = 1;
  // 表示调用add(undefined)的JavaScript代码  let first = second;  let second = 1;

    调用add(undefined, 1)函数,因为当first初始化时second尚未初始化,所以会导致程序抛出错误,此时second尚处于临时死区中,

      所有引用临时死区中绑定的行为都会报错。初始化后变量会移出临时死区,反过来说引用了还在临时死区 中的变量都是未初始化的,会抛出referenceerror错误。

  函数参数有自己的作用域和临时死区,其与函数体的作用域是各自独立的,也就是说参数的默认值不可访问函数体内声明的变量。

                    还可关注作者 【菜鸟1024】 更多文章请识别以下二维码并关注交流

参考资料

《深入理解ES6》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值