这节学习ES6中对函数新增的方法和属性。
1.新增函数的参数默认值
参考S6系列第二篇:http://www.cnblogs.com/diweikang/p/8976854.html
2.新增了函数的rest参数
参考ES6系列第二篇:http://www.cnblogs.com/diweikang/p/8976854.html
3.length属性
作用:获取函数预期传入的参数个数。
指定默认值后,length属性将返回没有指定默认值参数的个数。
(function (a) {}).length // 1 (function (a = 5) {}).length // 0 (function (a, b, c = 5) {}).length // 2
注意:如果设置了默认值的参数不是尾参数,length属性也不再计入后面的参数。
(function (a = 0, b, c) {}).length // 0 (function (a, b = 1, c) {}).length // 1
4.严格模式
严格模式是ES5中新增语法的,限制指定的代码在更严格的模式下执行。通常在脚本开头或函数头部添加"use strict"表达式来声明。
<1>ES5开始,函数内部可以显示声明严格模式。
function doSomething(a, b) { 'use strict'; // ... }
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 } };
规定原因:函数内部声明的严格模式,限制函数参数和函数体都必须是严格模式执行。只有执行函数体的时候才能知道函数是否是严格模式,但是函数时先执行函数参数,再执行函数体的。这就导致参数如果不遵守严格模式,函数体中又显示声明严格模式,函数进行就会报错。
// 严格模式八进制使用0o前缀表示 function doSomething(value = 070) { 'use strict'; return value; }
上面函数执行就会报错。
如何规避这种限制:
<1>、设定全局性的严格模式。
'use strict'; function doSomething(a, b = a) { // ... }
<2>、把函数包装在一个无参数的立即执行函数里面。
const doSomething = (function () { 'use strict'; return function(value = 42) { return value; }; }());
5.name属性
ES6新增函数的name属性,返回该函数的函数名。
<1>将一个匿名函数赋值给一个变量,ES5的name属性会返回空字符创,ES6的name属性会返回实际的函数名称。
var f = function () {}; // ES5 f.name // "" // ES6 f.name // "f"
<2>将一个具名函数赋值给一个变量,ES5和ES6的name属性都会返回这个具名函数的名称。
const bar = function baz() {}; // ES5 bar.name // "baz" // ES6 bar.name // "baz"
<3>构造函数返回的函数实例,name属性值为anonymous。
(new Function).name // "anonymous"
<4>将bind返回的函数,name属性值会加上bound前缀。
function foo() {}; foo.bind({}).name // "bound foo" (function(){}).bind({}).name // "bound "
6.箭头函数
ES6允许使用"箭头"(=>)定义函数。
<1>箭头函数需要一个参数。
var f = v => v; // 等同于 var f = function (v) { return v; };
<2>箭头函数不需要或者需要多个参数,使用括号将参数部分括起来。
var f = () => 5; // 等同于 var f = function () { return 5 }; var sum = (num1, num2) => num1 + num2; // 等同于 var sum = function(num1, num2) { return num1 + num2; };
<3>箭头函数代码块多余一条语句,就要使用大括号括起来,并使用return语句返回。
var sum = (num1, num2) => { return num1 + num2; }
<4>如果箭头函数需要返回一个对象,对象外面需要小括号括起来,否则会被当成代码块返回。
// 报错 let getTempItem = id => { id: id, name: "Temp" }; // 不报错 let getTempItem = id => ({ id: id, name: "Temp" });
<5>如果箭头函数只有一行语句,且不需要返回值,可以采用下面的写法。
let fn = () => void doesNotReturn();
<6>箭头函数与变量解构结合使用。
const full = ({ first, last }) => first + ' ' + last; // 等同于 function full(person) { return person.first + ' ' + person.last; }
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]]
<8>箭头函数中的this对象。
注意:箭头函数中的this总是指向函数定义生效时所在的对象。
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
上面代码中,setTimeout
的参数是一个箭头函数,这个箭头函数的定义生效是在foo
函数生成时,而它的真正执行要等到 100 毫秒后。如果是普通函数,执行时this
应该指向全局对象window
,这时应该输出21
。箭头函数导致this
总是指向函数定义生效时所在的对象(本例是{id: 42}
),所以输出的是42
。
再看一个例子:
function Timer() { this.s1 = 0; this.s2 = 0; // 箭头函数 setInterval(() => this.s1++, 1000); // 普通函数 setInterval(function () { this.s2++; }, 1000); } var timer = new Timer(); setTimeout(() => console.log('s1: ', timer.s1), 3100); setTimeout(() => console.log('s2: ', timer.s2), 3100); // s1: 3 // s2: 0
分析:箭头函数中的this指向箭头函数定义生效时所在的对象,第一个定时器中的this指向timer对象,第二个定时器指向调用它的对象(全局对象),3100ms后s1更新了3次,而s2并没有更新,所以结果是3和0。
总结:箭头函数没有自身的this对象。
1.函数体中this对象,定义时所在的对象,不是函数调用时所在对象。
2.不可以当构造函数,也就是不可以使用new命令。
3.不可以使用arguments对象,该对象在箭头函数体内不存在。
<9>双冒号运算符
ES6中提出使用双冒号(::)函数绑定的运算符,替代call、apply、bind调用。
双冒号左边是一个对象,右边是一个方法,表示将右边的函数绑定到左边的对象上。
foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments); const hasOwnProperty = Object.prototype.hasOwnProperty; function hasOwn(obj, key) { return obj::hasOwnProperty(key); }
双冒号左边为空,右边是一个对象的方法,表示将函数绑定到这个对象上。
var method = obj::obj.foo; // 等同于 var method = ::obj.foo; let log = ::console.log; // 等同于 var log = console.log.bind(console);
总结:
上面这些就是我们在开发中,可能会用到的ES6中关于函数的扩展的属性和方法,还是需要多练习多理解。