函数的 name 属性
函数的name
属性,返回该函数的函数名。
var f = function () {};
// ES5 之前返回的是一个空的字符串
console.log(f.name); // f
每次声明一个function
的时候相当于new Function
进行一次实例化。Function
构造函数返回的函数实例,name
属性的值为anonymous
。
console.log(Function); // ƒ Function() { [native code] }
var test = new Function();
console.log(test.name); // anonymous
bind
返回的函数,name
属性值会加上bound
前缀。
function foo() {};
console.log(foo.bind({}).name); // bound foo
console.log(foo.call({}).name); // Cannot read properties of undefined (reading 'name')
// call 相当于函数执行后没有返回值,所以报错
函数默认值
在ES5
中如果我们想要给一个函数的形参设置默认值改怎么做呢?
function foo(x, y) {
x = x || 1;
y = y || 2;
console.log(x + y); // 6
}
foo(4);
ES6
简化了函数默认值的写法:
function foo(x = 1, y = 2) {
console.log(x + y); // 4
}
foo(4);
使用let
声明的变量不能和函数的形参同名:
let x = 1;
function foo(x = 2) {
let x = 2; // Identifier 'x' has already been declared
console.log(x);
}
foo();
数组解构赋值
ES5
假如我们想要连续声明多个变量需要这么写:
let a = 1,
b= 2,
c = 3;
console.log(a, b, c); // 1 2 3
ES6
新增了解构的方式进行声明变量,这有点类似按照对应的下标从数组中拿数据:
let [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1 2 3
// 解构的值会受数组顺序的影响
let [b, a, c] = [1, 2, 3];
console.log(a, b, c); // 2 1 3
需要注意的是等号的两边数据结构必须一致:
let [d, [e], [f]] = [1, [2], [3]];
console.log(d, e, f); // 1 2 3
解构失败的值会返回undefind
:
let [d, [e], [f]] = [1, [2], []];
console.log(d, e, f); // 1 2 undefind
如果解构的参数比实际的实际少也是正常执行的,这样的情况称为「不完全结构」:
let [, [e], [f]] = [1, [2], [3]];
console.log(e, f); // 2 3
解构赋值还可以设置默认值,利用=
表示设置为一个默认值,这和函数的默认值有点像:
let [d, [e], [f = 6]] = [1, [2], []];
console.log(d, e, f); // 1 2 6
默认值还可以是一个函数:
function foo() {
return "foo";
}
let [a = foo()] = [, 1];
console.log(a); // 'foo'
解构赋值存在隐式转换的过程:
const [a, b, c, d, e] = "hello";
console.log(a, b, c, d, e); // h e l l o
const { length: len } = "hello";
console.log(len); // 5
const { toString: s } = 123;
console.log(s); // function
⚠️ 注意:除了**undefind**
其他类型的**false**
值都将被正常获取:
let [a, b = 2, c = 3, d = 4] = [1, undefined, null, false];
console.log(a, b, c, d); // 1 2 null false
解构赋值也存在暂时性死区:
// 在定义 y 之前无法访问 y
let [x = y, y = 1] = []; // Cannot access 'y' before initialization
console.log(x, y);
// 在 x 之后访问 x 这样是容许的
let [x = 1, y = x] = [];
console.log(x, y); // 1 1
不能重复声明:
let x = 5;
// 不能重复声明 x
let [x = 1, y = x] = []; // Identifier 'x' has already been declared
console.log(x, y);
对象解构赋值
以上是数组的解构赋值,在ES6
中针对对象的语法也有一些新增。
当对象的属性名和外部变量同名时可以进行简写,函数也可以简写:
// ES5
var name = "张三";
let sex = "male";
var person = {
name: name,
sex: sex,
age: 20,
eat: function() {
console.log("吃饭");
},
};
// ES6
var name = "张三";
let sex = "male";
var person = {
name,
sex,
age: 20,
eat() {
console.log("吃饭");
},
};
ES6
容许对象的属性名是一个动态的:
let firstName = "zhang";
let secondName = "san";
let person = {
[firstName + secondName]: "zhangsan",
};
console.log(person); // {zhangsan: zhangsan}
接下来看看对象的结构赋值。
对象的解构赋值同样需要遵循=
两边数据结构一致的行为:
let { a1: a, b: b, c: c } = { a1: 1, b: 2, c: 3 };
console.log(a, b, c); // 1 2 3
以上代码可以看到**:**
前面才是需要解构的参数名,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者!!!:
后面相当于是对象的属性重命名。
当定义的变量和属性名同名的时候一样可以进行简化:
let { a, b, c } = { a: 1, b: 2, c: 3 };
console.log(a, b, c); // 1 2 3
对象解构赋值也可以设置默认值:
let { a = "a", b, c } = { b: 2, c: 3, e: 4, f: 5 };
console.log(a, b, c); // 'a' 2 3
解构失败的值会返回undefind
:
let { a, b, c } = { b: 2, c: 3, e: 4, f: 5 };
console.log(a, b, c); // undefined 2 3
同样也会出现「不完全解构」的行为:
let { a, b, c } = { a: 1, b: 2, c: 3, e: 4, f: 5 };
console.log(a, b, c); // 1 2 3
和数组解构赋值不同的是,对象解构赋值不存在顺序取值的问题,只要属性名和变量名一致就行:
let { a, b, c } = { b: 2, a: 1, c: 3 };
console.log(a, b, c); // 1 2 3
对象如何进行多层解构赋值呢?
let person = {
name: "张三",
age: 40,
son: {
name: "张四",
age: 30,
son: {
name: "张五",
age: 20,
},
},
};
let { son: { son: son1 } } = person;
console.log(son1); // {name: "张五", age: 20}