函数的拓展

本文详细介绍了ECMAScript 6中函数的新特性,包括参数默认值、解构赋值、rest参数、箭头函数等内容,并解释了这些特性如何提高代码的可读性和维护性。

本系列属于阮一峰老师所著的ECMAScript 6 入门学习笔记


函数参数的默认值
function Point(x =0,y=0){
  this.x = x
  this.y = y
}

const p = new Point()
p // {x:0,y:0}

// 参数变量是默认声明的,所以不能用let或const再次声明
function(x = 5){
  let x = 1 // error
  const x = 2 // error
}

// 使用参数默认值时,函数不能有同名参数
function foo(x,x,y=1){
    // ...
}
// SyntaxError: Duplicate parameter name not allowed in this context

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

foo() // 100

x=100
foo() // 101
参数默认值与解构赋值默认值结合使用
function(x,y=5){
  console.log(x,y)
}

foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined

// 如果调用foo时没提供参数,变量x和y就不会生成。通过提供函数参数的默认值,可以避免
function foo({x,y=5}={}){
  console.log(x,y)
}

foo() // undefined 5
参数默认值的位置
// 通常情况下,定义了默认值的参数,应该是函数的尾参数。如果非尾部设置默认值,实际上这个参数是没法省略的
// 例一
function(x=1,y){
  return [x,y]
}

f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]

//例二
function f(x,y=5,z){
  return [x,y,z]
}

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]
// 上面代码中,有默认值的参数都不是尾参数。这时,无法只省略该参数,而不省略后面的参数,除非显式输入undefined,null没有这个效果
函数的length属性

指定了默认值之后,函数的length属性将返回没有指定默认值的参数个数。

(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2

这是因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。同理,rest 参数也不会计入length属性。

(function(...args) {}).length // 0

如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。

(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
作用域

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

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

let x = 1
function f(y=x){
  let x = 2
  console.log(y)
}
f() // 1

// 若此时全局变量x不存在,就会报错。若参数写成x=x形成单独作用域,会形成暂时性死区报错

如果函数的默认值是一个函数,该函数的作用域也遵守这个规则

let foo = 'outer'

function bar(func = () => foo){
  let foo = 'inner'
  console.log(func())
}
bar() // outer
rest参数

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

function add(...values){
  let sum = 0
  for(let val of values){
    sum += val
  }
  return sum
}

add(2,3,5) // 10

// 注意,rest参数之后不能再有其他参数,否则会报错
// 函数的length属性,不包括rest参数
严格模式

从ES5开始,函数内部尅设定为严格模式。ES6做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者拓展运算符,那么函数内部就不能设定为严格模式,否则会报错。

// 报错
function doSomething(value = 070){
  'use strict'
  return value
}

// 两种方法可以规避这种限制
// 一、设定全局性的严格模式
'use strict'
function doSomething(a,b=a){
  // code
}

// 二、把函数包在一个无参数的立即执行函数里面
const doSomething = (function(){
  'use strict'
  return function(value = 42){
    return value
  }
}())
name 属性

函数的name属性,返回该函数的函数名。这是一个早就被浏览器支持,直到ES6才写入标准的属性

function foo(){}
foo.name // 'foo'

// 对于匿名函数,ES6的name属性会返回实际的函数名,ES5则返回空字符串
var f = function(){}

// ES5
f.name // ''

// ES6
f.name // 'f'

// 对于具名函数,ES5和ES6的name属性都返回这个具名函数原本的名字

// Function构造函数返回的函数实例,name属性的值为anonymous
(new Function).name // 'anonymous'

// bind返回的函数,name属性值会加上bound前缀
function foo(){}
foo.bind({}).name // 'bound foo'
(function(){}).bind({}).name // 'bound '
箭头函数

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

var f = v => v

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

// 无参数或多参数写法
var f = () => 5
var sum = (num1,num2) => num1 + num2

// 返回对象
let getTempItem = id => ({id:id,name:'Temp'})

// 只有一行语句,且不需要返回值
let fn = () => void doesNotReturn()

// 与变量解构结合使用
const full = ({first,last}) => first + '' + last

// 与rest参数结合
const numbers = (...nums) => nums
numbers(1,2,3,4,5) // [1,2,3,4,5]

const headAndTail = (head,...tail) => [head,tail]
headAndTail(1,2,3,4,5) // [1,[2,3,4,5]]

使用注意点

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

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

转载于:https://www.cnblogs.com/pengzhixin/p/7807908.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值