介绍
本次介绍ES6函数和对象的一些扩展,更多详情参考:函数的扩展,对象的扩展
函数
函数参数的默认值
直接为函数的参数指定默认值1
2
3
4
5
6function test(x,y='world'){
console.log(x,y);
}
test('hello'); //hello world
test('hello','hello'); //hello hello
参数变量是默认声明的,所以不能用let或const再次声明1
2
3
4function test(x,y='world'){
let y = 'world'; //error
console.log(x,y); //error
}
参数默认值的位置
1 | function f(x = 1, y) { |
作用域1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26//一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。
//等到初始化结束,这个作用域就会消失。
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) // 2
f() //undefined
//上面代码中,参数y的默认值等于变量x,在作用域里,x指向的是第一个参数x,而不是全局变量x。x没赋值时,y就是undefined。
//另一种情况
var x = 1;
function f(y = x) {
console.log(y);
}
f(2); //2
f(); //1
//这个作用域里面,变量x本身没有定义,所以指向外层的全局变量x
rest 参数
ES6 引入 rest 参数(形式为…变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。
当你不确定参数个数时,你可以这样做1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var sum;
function add(...args){
for(var v of args){
sum+=v;
}
return sum;
}
add(1,2); //3
add(1,2,3); //6
add(1,2,3,4,5,6); //21
//add函数是一个求和函数,利用 rest 参数,可以向该函数传入任意数目的参数。
//这就是扩展运算符的使用,rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中
箭头函数
这个使用率很高的。
ES6 允许使用“箭头”(=>)定义函数1
2
3
4
5
6let fn = v => v*2;
//等同于
let fn = function(v){
return v*2;
}
console.log(fn(2)); //4
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。1
2
3
4
5
6
7
8
9
10
11let fn = () => 2;
//等同于
let fn = function(){
return 2;
}
let fn = (num1,num2) => num1+num2
//等同于
let fn = function(num1,num2){
return num1+num2;
}
如果加上{},return不能省略的
1 | //当不写{},且没有其他操作时,默认返回值 |
如果箭头函数只有一行语句,且不需要返回值1
let fn = () => alert(1)
this
尤其要注意箭头函数里的this指向,
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 }); // id: 42
//定时器里有个箭头函数,它的this指向的是定义时的对象,即foo。而foo的this指向了{id:42}这个对象,所以结果是42。
//现在换回ES5的写法
setTimeout(function(){
console.log('id:', this.id);
}, 100);
//此时this指向的是window对象,所以this.id指的就是全局变量id,为21。
另外要注意的:
箭头函数不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
对象
属性的简洁表示法
ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
1 | //属性简写 |
属性名表达式
在ES5中,使用字面量方式定义对象(使用大括号),只能使用标识符定义属性名:1
2
3
4var obj = {
foo: true,
abc: 123
};
现在ES6允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内:1
2
3
4
5
6
7
8let key = 'num';
let obj = {
[key]:123,
['na' + 'me']:'jhon'
}
console.log(obj); // {num: 123, name: "jhon"}
表达式还可以用于定义方法名:1
2
3
4
5
6
7let obj1 = {
['h' + 'ello'](){
console.log('hi');
}
}
obj1.hello(); //hi
注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]
:1
2
3
4
5
6const keyA = {a:1};
let obj2 = {
[keyA]:'A'
}
console.log(obj2); //{[object Object]: "A"}
Object.assign
合并对象
Object.assign方法用于对象的合并,将源对象的所有可枚举属性,复制到目标对象。第一个参数是目标对象,后面的参数都是源对象。1
2
3
4
5
6
7
8
9let o1 = {'a':1};
let o2 = {'b':2};
let o3 = {'c':3};
Object.assign(o1,o2,o3);
console.log(o1); //{a: 1, b: 2, c: 3}
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
1 | //将上面例子改变一下 |
拷贝
1 | var obj1 = { |
需要注意的是,Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。1
2
3
4
5
6
7
8
9
10
11var obj1 = {
'a':{
'b':1
}
}
var obj2 = Object.assign({},obj1);
obj1.a.b = 2;
console.log(obj2.a.b); //2