这篇文章主要介绍了函数的扩展,函数的扩展只要有三个方面:函数
1 参数的默认值优化
2 箭头函数this
3 关于尾调用的优化prototype
能够在直接定义函数的时候,定义好参数若是没传或者传错 undefined。rest
//解构的基本用法 //用法1: function log(x, y = 'World') { console.log(x, y); } log('Hello'); //Hello World log('Hello', 'China'); /* Hello China */ log('Hello', ''); /* Hello */ 参数的默认值只有在没传时才会生效。 //用法2: function week({ x, y = 5 }) { console.log(x, y); } week({}); /* undefined 5 */ week({x: 1}); /* 1 5 */ week({x: 1, y: 2}); /* 1 2 */ week(); /* TypeError: Cannot read property 'x' of undefined */ //用法3: function week({x, y = 5} = {}) { console.log(x, y); } week(); /* undefined 5 */
解构和参数的默认值须要注意的点:code
参数的变量已经默认声明,不能用let或const再次声明对象
function week(x = 5) { let x = 1; const x = 2; } /* SyntaxError: Identifier 'x' has already been declared */
函数不能有同名参数,由于参数的变量已经默认声明因此不能再次声明递归
function week(x, x, y = 1) { /* ... */ } /* SyntaxError: Duplicate parameter name not allowed in this context */
参数默认值是惰性求值token
当咱们真正运算走这个函数的时候,它才会去处理默认的参数作用域
let x = 99; function week(p = x + 1) { console.log(p); } week(); /* 100 */ x = 100; week(); /* 101 */
参数默认值通常用于尾部,好比一个函数
length属性,也就是函数的name和let,返回没有指定默认值的参数个数
(function (a) {}).length; //1 (function (a = 5) {}).length; //0 (function (a, b, c = 5) {}).length; //2 (function (a = 0, b, c) {}).length; //0 (function (a, b = 1, c) {}).length; //1 (function(...args) {}).length; //0
设置了参数的默认值,参数会造成一个单独的做用域
var 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
好比一个函数的argument咱们知道这是函数的参数,argument其实是官方不推荐的一种用法。
function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(2, 5, 3); /* 10 */ function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); } const sortNumbers = (...numbers) => numbers.sort();
function week() {}week.name;// "week" * var f = function () {};f.name // ""// ES6f.name // "f"
箭头函数主要的两点是:第一点它的this指向是在它当时定义所在的做用域,第二个是它没有一个做用域的提高。
// 单个参数 var f = v => v; var f = function (v) { return v; }; // 多个参数 var sum = (num1, num2) => num1 + num2; var sum = function(num1, num2) { return num1 + num2; }; // return,有两种场景,箭头函数里面直接写return或者不写的话箭头函数就会默认把这个结果当成一个return。 也就是说当咱们返回一个对象时,没有return语句的时候咱们须要再对象外面再包一个括号 var sum = (num1, num2) => { return num1 + num2; } // 1 返回对象 let getTempItem = id => { id: id, name: "Temp" }; // 2 Unexpected token : let getTempItem = id => ({ id: id, name: "Temp" }); // 结合解构 const full = ({ first, last }) => first + ' ' + last; // rest const numbers = (...nums) => nums; numbers(1, 2, 3, 4, 5); // [1,2,3,4,5]
箭头函数使用的注意点:
函数体内的this对象指向定义时所在的对象而不是使用时所在的对象
function week() { setTimeout(() => { console.log('id:', this.id); }, 100); } //定义全局id(使用时的所在id) var id = 21; //调用,改变了this的值 week.call({ id: 42 }); // 42 function week() { return () => { return () => { return () => { console.log('id:', this.id); }; }; }; } //定义时的id=1,决定了它的做用域,所以下面的t1,t2,t3的输出结果均为1 var f = week.call({id: 1}); var t1 = f.call({id: 2})()(); var t2 = f().call({id: 3})(); var t3 = f()().call({id: 4}); // 1 // 对象不构成做用域 const cat = { lives: 9, jumps: () => { this.lives--; } }
不能够看成构造函数,由于定义的时候是全局的
不可使用argument对象,这是一个规定,须要使用rest来代替
不可使用yield命令
通常用于严格模式,也就是说在严格模式下面,ES6作了一个尾调用的优化;可是在非严格模式下虽然也可使用尾调用,可是没有优化。
尾调用基本概念:最后一步是调用另外一个函数,不适用于外部变量时只保留内层函数的调用帧(外部的变量不该该保存在return这个函数里面,也就是返回的return并不使用这个做用域)。
function f(x){ return g(x); }
function factorial(n) { if (n === 1) return 1; return n * factorial(n - 1); } factorial(5); // 尾递归 function factorial(n, total) { if (n === 1) return total; return factorial(n - 1, n * total); } factorial(5, 1)
func( 'week', 'month', );