系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
文章目录
1. 函数参数默认值
1.1. 基本用法
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello'); // Hello World
log('Hello', 'Friend'); // Hello Friend
log('Hello', ''); // Hello
log(undefined); // undefined 'World'
1.2. 与解构赋值默认值结合使用
// 写法一
function m1({x = 0, y = 0} = {}) {
return [x, y];
}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]
// x 和 y 都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]
// x 有值,y 无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]
// x 和 y 都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]
m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
1.3. 函数length属性
- 指定了默认值以后,函数的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
1.4. *************函数参数默认值引起的第三作用域问题
- 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
- 参考这篇文章
关于 ES6 参数默认值形成的第三作用域问题 - 上面这篇文章的小节:
1 .函数形参指定了默认值时,将形成一个第三作用域,即参数作用域,此作用域将作为函数作用域的父级。
2 .函数内let声明的局部变量名与形参名一致时,在解析阶段就会报错。
3 .函数内诸如var x(未赋值)声明的局部变量名与形参名一致时,可忽略当前代码行。
var x = 20;
function fun(x = 1) {
let x = 10; // SyntaxError: Identifier 'x' has already been declared
console.log(x);
}
fun();
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) // 2
// 调用函数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。
function f(y = x) {
let x = 2;
console.log(y);
}
f() // ReferenceError: x is not defined
var x = 1;
function foo(x = x) {
// ...
}
foo() // ReferenceError: Cannot access 'x' before initialization
// 参数x = x形成一个单独作用域。实际执行的是let x = x,由于暂时性死区的原因,这行代码会报错。
2. rest参数
- ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
- arguments对象不是数组,而是一个类似数组的对象。为了使用数组的方法,必须使用Array.from先将其转为数组。
- rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。
// arguments变量的写法
function sortNumbers() {
return Array.from(arguments).sort();
}
// rest参数的写法
const sortNumbers = (...numbers) => numbers.sort();
- rest 只能是最后一个参数,否则会报错。
// 报错
function f(a, ...b, c) {
// ...
}
- 函数的length属性,不包括 rest 参数。
(function(a) {}).length // 1
(function(...a) {}).length // 0
(function(a, ...b) {}).length // 1
3. 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"
4. 箭头函数
4.1. 写法
- 基本写法
function() { }
等于
()=> { }
- 无参数
let fn = () => 'hello world';
- 一个参数
let add = val => { return val };
let add = val => (val);
let add = val => val;
let add = val => { return val + 5 };
let add = val => (val + 5);
let add = val => val + 5;
- 两个及多个参数
let happiness = (you, i) => { return you + ' love ' + i + ' ,' + i + ' love ' + you + ' ♡' }
let happiness = (you, i) => (you + ' love ' + i + ' ,' + i + ' love ' + you + ' ♡')
let happiness = (you, i) => you + ' love ' + i + ' ,' + i + ' love ' + you + ' ♡'
console.log(happiness('FU', 'CW'));
// FU love CW ,CW love FU ♡
4.2. 优点
- 语法简明
// 与rest函数结合,高效变数组
const numbers = (...nums) => nums;
console.log(numbers(1, 2, 3, 4, 5)); //[1, 2, 3, 4, 5]
- 简化回调函数,隐式返回
const pingfang = [1, 2, 3].map(x => x * x);
console.log(pingfang); // [1, 4, 9]
- this值继承父作用域
4.3. 使用注意点
- 箭头函数没有自己的this对象。
- 不能当作构造函数,不可以对箭头函数使用
new
命令。 - 不可以使用arguments对象。
- 不能使用
apply()
call()
bind()
去改变this的指向。
4.4. 不适宜场合
- 定义对象的方法,且该方法内部包括this。
由于这个原因,对象的属性建议使用传统的写法定义,不要用箭头函数定义。
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
- 上面代码,this指向全局对象,不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。
- 需要动态this的时候。
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
- 上面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。