7

ES6 系列四:函数的扩展

 3 years ago
source link: https://segmentfault.com/a/1190000039836295
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

"Code tailor",为前端开发者提供技术相关资讯以及系列基础文章,微信关注“小和山的菜鸟们”公众号,及时获取最新文章。

在开始学习之前,我们想要告诉您的是,本文章是对阮一峰《ECMAScript6 入门》一书中 "函数的扩展" 章节的总结,如果您已掌握下面知识事项,则可跳过此环节直接进入题目练习

  • 函数参数的默认值
  • rest 参数

如果您对某些部分有些遗忘,👇🏻 已经为您准备好了!

函数的扩展学习

函数参数的默认值

为函数的参数指定默认值

// ES5写法
function log(x, y) {
  y = y || 'World'
  console.log(x, y)
}

log('Hello') // Hello World

// ES6写法
function log(x, y = 'World') {
  console.log(x, y)
}

log('Hello') // Hello World

优点:

  • 阅读代码的人,可以立刻意识到哪些参数是可以省略的,不用查看函数体或文档
  • 有利于将来的代码优化,即使未来的版本在对外接口中,彻底拿掉这个参数,也不会导致以前的代码无法运行

注意:

  • 参数变量是默认声明的,所以不能用 letconst 再次声明
function foo(x = 5) {
  let x = 1 // error
  const x = 2 // error
}
  • 使用参数默认值时,函数不能有同名参数
// 不报错
function foo(x, x, y) {
  // ...
}

// 报错
function foo(x, x, y = 1) {
  // ...
}
  • 参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的
let x = 99
function foo(p = x + 1) {
  console.log(p)
}

foo() // 100

x = 100
foo() // 101

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

var x = 1
function foo(
  x,
  y = function () {
    x = 2
  },
) {
  var x = 3
  y()
  console.log(x)
}

foo() // 3
x // 1

// 分割线

var x = 1
function foo(
  x,
  y = function () {
    x = 2
  },
) {
  x = 3
  y()
  console.log(x)
}

foo() // 2
x // 1

rest 参数

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用 arguments 对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function add(...values) {
  let sum = 0

  for (var val of values) {
    sum += val
  }

  return sum
}

add(2, 5, 3) // 10

//上面代码的add函数是一个求和函数,利用 rest 参数,可以向该函数
//传入任意数目的参数。

注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

ES6 允许使用“箭头”(=>)定义函数。

var f = (v) => v

// 等同于
var f = function (v) {
  return v
}

如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

var f = () => 5
// 等同于
var f = function () {
  return 5
}

var sum = (num1, num2) => num1 + num2
// 等同于
var sum = function (num1, num2) {
  return num1 + num2
}

如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用 return 语句返回。

var sum = (num1, num2) => {
  return num1 + num2
}

箭头函数有几个使用注意点:

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
  • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。

一:以下代码输出什么

var x = 1
function foo(x, y = () => (x = 5)) {
  x = 9
  y()
  console.log(x)
}

foo()

二:以下代码输出什么

const shape = {
  radius: 10,
  diameter() {
    return this.radius * 2
  },
  perimeter: () => 2 * Math.PI * this.radius,
}

shape.diameter()
shape.perimeter()
  • A: 20 and 62.83185307179586
  • B: 20 and NaN
  • C: 20 and 63
  • D: NaN and 63

三:解释下述代码(含义、运行结果以及作用)。

f1 = (x) => (y) => (z) => x * y * z

一、

Answer:5

首先需要看明白函数foofunction foo(x, y = () => x = 5),重点在于第二个y = () => x = 5,意思为需要给与foo函数一个函数,如果没有,那么 y 代表的就是

;() => {
  x = 5
}

这一个函数,这里调用 foo,并没有给与第二个函数,那么执行的时候,y()实际上就是将 x 赋值为 5,因此打印出来为 5


二、

Answer:B

首先需要了解,在箭头函数中,this的指向和在普通函数中不同,箭头函数中this指向在定义的时候就确定好了。在diameter函数中,通过this.radius访问的就是shape中的radius,为 10

但是,在perimeter函数中,后面通过this.radius访问的radius并不是shape中的radius,在外层寻找找不到,因此返回NaN。因此答案为20 and NaN


三、

首先,这样子使用箭头函数逻辑不是很清楚,将其转换为普通函数:

function f1(x) {
  return function f2(y) {
    return function f3(z) {
      return x * y * z
    }
  }
}

含义:将三个数相乘

运行结果:f1(x)(y)(z)===x*y*z

最外层,f1 是一个带一个形参的函数,返回值是一个带一个形参的函数 f2,f1(x)(y)(z)->f2(y)(z),f2 返回值是一个带一个形参的函数 f3,f2(y)(z)->f3(z),因为返回的函数是在 f1f2 中定义的,根据作用域链,可以取到 xy 的值,所以f3的返回值为x*y*z,最后 f1(x)(y)(z)===x*y*z

ES 6 系列的 函数的扩展,我们到这里结束啦,谢谢各位对作者的支持!你们的关注和点赞,将会是我们前进的最强动力!谢谢大家!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK