Js函数的扩展
1:参数的默认值(会形成一个单独的作用域)
可以在直接定义函数的时候,定义好参数如果没传或者传错 undefined。
//解构的基本用法
//用法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 */解构和参数的默认值需要注意的点:
参数的变量已经默认声明,不能用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 */参数默认值是惰性求值
当我们真正运算走这个函数的时候,它才会去处理默认的参数
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();
//12:rest参数,只能有一个参数,部分场景可以替代argument、类似于argument。
比如一个函数的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();3:严格模式,在严格模式下,使用了默认值、解构赋值或者扩展不能使用严格模式。
4:name 返回函数名
function week() {}
week.name;
// "week" *
var f = function () {};
f.name // ""
// ES6
f.name // "f"5:箭头函数
箭头函数主要的两点是:第一点它的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--;
}
}6:尾调用
一般用于严格模式,也就是说在严格模式下面,ES6做了一个尾调用的优化;但是在非严格模式下虽然也可以使用尾调用,但是没有优化。
尾调用基本概念:最后一步是调用另一个函数,不适用于外部变量时只保留内层函数的调用帧(外部的变量不应该保存在return这个函数里面,也就是返回的return并不使用这个作用域)。
function f(x){
return g(x);
}7:尾递归(会有一个调用栈的堆积)
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)8:函数参数的尾逗号,方便代码版本管理
func(
'week',
'month',
);本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!