文章目录
ES6函数的扩展
1.0 函数参数的默认值
ES6 之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
function log(x, y) { y = y || 'World'; console.log(x, y); } log('Hello') // Hello World log('Hello', 'China') // Hello China log('Hello', '') // Hello World
**ES6之后可以直接在函数的参数中指定默认值, 如下代码演示: **
function f(x, y = 5, z) { return [x, y, z]; }
函数的 length 属性
指定了默认值以后, 函数的
length
属性, 将返回没有指定默认值的参数个数. 也就是说, 指定了默认值之后,length
属性将是真.(function (a) {}).length // 1 (function (a = 5) {}).length // 0 (function (a, b, c = 5) {}).length // 2
上述代码中
length
属性的返回值, 等于函数的参数个数减去指定了默认值的参数个数. 比如, 上面最后一个函数, 定义了3个参数, 其中有一个参数c
指定了默认值, 因此length
属性等于3
减去1
, 最后得到2
.这是因为
length
属性的含义是, 该函数预期传入的参数个数. 某个参数指定默认值以后, 预期传入的参数个数就不包括这个参数了. 同理, 马上即将提到的rest
参数也不会计入length
属性.(function(...args) {}).length // 0
如果设置了默认值的参数不是尾参数, 那么
length
属性也不再计入后面的参数了(function (a = 0, b, c) {}).length // 0 (function (a, b = 1, c) {}).length // 1
1.1.1 函数参数默认值 作用域
一旦设置了参数的默认值, 函数进行声明初始化时, 参数会形成一个单独的作用域(context) . 等到初始化结束, 这个作用域就会消失. 这种语法行为, 在不设置参数默认值时, 是不会出现的.
var x = 1; function f(x, y = x) { console.log(y); } f(2) // 2
上述代码中, 参数
y
的默认值等于变量x
, 调用函数f
时, 能形成一个单独的作用域. 在这个作用域里面, 默认值变量x
指向第一个参数x
, 而不是 全局变量x
, 所以输出是2
.再看下面的例子
# 注意, 是参数部分形成了一个单独的作用域, 参数部分形成的单独作用域 和函数体的作用域不是一个作用域. let x = 1; function f(y = x) { let x = 2; console.log(y); } f() // 1
上面代码中, 函数
f
调用时, 参数y=x
形成一个 单独 的作用域, 在这个作用域里面, 变量x
本身没有定义, 所以指向外层的全局变量x
. 函数调用时, 函数体内部的局部变量x
影响不到默认值变量x
. 因为 函数体内部的局部变量x
是一个单独的作用域, 参数部分的变量x
也是一个单独的作用域, 它们是两个不同的作用域.如果此时, 全局变量
x
不存在, 就会报错.function f(y = x) { let x = 2; console.log(y); } f() // ReferenceError: x is not defined
1.1.2 函数参数默认值作用域容易引起报错问题
下面这样写, 也会报错
var x = 1; function foo(x = x) { // ... } foo() // ReferenceError: x is not defined
上面代码中, 参数
x = x
形成一个单独的作用域. 实际执行的是let x = x
, 由于暂时性死区的原因, 这行代码会报错 “x未定义”.如果实在不理解上述问题, 可以和下面例子对比理解:
var x = 1; var y = 2; function foo(x = y) { console.log(x); // 2 } function bar(x = x){ // x is not defined console.log(x); } foo() bar()
对比:
对于
foo
函数, 函数默认值是x=y
, 实际上执行的是let x = y
, 而用 let 声明的变量x
存在暂时性死区, 但是 变量y
并没有暂时性死区, 所以 变量y
可以向外查找到全局作用域中的 变量y
.但是
对于
bar
函数, 函数默认值是x=x
, 实际上执行的是let x = x
, 而用let
声明的变量x
存在暂时性死区, 所以将 等号右边的x
赋值给等号左边的x
的时候, 由于x
的暂时性死区的问题, 会导致出现x is not defined
的 未定义问题.
如果函数的默认值仍然是一个函数, 该函数的作用域也遵守这个规则, 如下所示
let foo = 'outer'; function bar(func = () => foo) { let foo = 'inner'; console.log(func()); } bar(); // outer
上面代码中,函数
bar
的参数func
的默认值是一个匿名函数,返回值为变量foo
。函数参数形成的单独作用域里面,并没有定义变量foo
,所以foo
指向外层的全局变量foo
,因此输出outer
。 如果全局中没有foo
变量, 则会报错.
2.0 rest参数
ES6引入 rest参数 (形式为
...变量名
), 用于获取函数的多余参数, 这样就不需要使用arguments
对象了. rest参数搭配的变量是一个数组, 该变量将多余的参数放入数组中.function sum(...values) { console.log(values); // rest参数搭配的变量values 是一个数组, 该变量 values 将多余的参数放入数组中. [ 1, 2, 3 ] let sum = 0; for (var val of values) { sum += val; } return sum } console.log(sum(1, 2, 3)); // 6
上面代码的
add
函数是一个求和函数,利用 rest 参数,可以向该函数传入任意个数的参数。
函数的
length
属性不包括rest
参数(function(a) {}).length // 1 (function(...a) {}).length // 0 (function(a, ...b) {}).length // 1
3.0 严格模式
从ES5开始, 函数内部可以设定严格模式.
function doSomething(a, b) { 'use strict'; // code }
ES2016 做了一点修改,规定只要函数参数使用了,那么函数内部就不能显式设定为严格模式,否则会报错
// 报错 function doSomething(a, b = a) { 'use strict'; // code } // 报错 const doSomething = function ({a, b}) { 'use strict'; // code }; // 报错 const doSomething = (...a) => { 'use strict'; // code }; const obj = { // 报错 doSomething({a, b}) { 'use strict'; // code } };
4.0 函数的name属性
函数的
name
属性, 返回该函数的函数名function foo() {} foo.name // "foo"
如果将一个匿名函数赋值给一个变量,ES5 的
name
属性,会返回空字符串,而 ES6 的name
属性会返回实际的函数名。var f = function () {}; // ES5 f.name // "" // ES6 f.name // "f"
如果将一个具名函数赋值给一个变量,则 ES5 和 ES6 的
name
属性都返回这个具名函数原本的名字。const bar = function baz() {}; // ES5 bar.name // "baz" // ES6 bar.name // "baz"
Function
构造函数返回的函数实例,name
属性的值为anonymous
(new Function).name // "anonymous"
bind
返回的函数,name
属性值会加上bound
前缀。function foo() {}; foo.bind({}).name // "bound foo" (function(){}).bind({}).name // "bound "
5.0 箭头函数
箭头函数比较常用, 我们这里不再做详细的解释案例, 只记录箭头函数的注意点
箭头函数使用注意点:
- 箭头函数体内的
this
对象, 就是定义时所在的对象, 而不是使用时所在的对象.- 箭头函数不可当做构造函数, 也就是说不可以使用
new
命令, 否则会抛出一个错误.- 箭头函数不可以使用
arguments
对象, 该对象在函数体内不存在, 如果要用 , 可以使用rest
参数代替.- 箭头函数不可以使用
yield
命令, 因此箭头函数不能作为Generator
函数.🏴 注意: 上面四点中, 第一点尤其值得注意.
this
对象的指向是可变的, 但在箭头函数中它是固定的.
总结
交流学习添加微信(备注技术交流学习):
Gene199302
该博客为学习阮一峰 ES6入门课所做的笔记记录, 仅用来留作笔记记录和学习理解