ES6函数和对象

介绍

本次介绍ES6函数和对象的一些扩展,更多详情参考:函数的扩展对象的扩展

函数

函数参数的默认值

直接为函数的参数指定默认值

1
2
3
4
5
6
function test(x,y='world'){
console.log(x,y);
}

test('hello'); //hello world
test('hello','hello'); //hello hello

参数变量是默认声明的,所以不能用let或const再次声明

1
2
3
4
function test(x,y='world'){
let y = 'world'; //error
console.log(x,y); //error
}

参数默认值的位置

1
2
3
4
5
6
7
8
9
10
function f(x = 1, y) {
return [x, y];
}

f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错
f(undefined, 1) // [1, 1]

//带有默认值的参数应该放在末尾,这样才可以省略

作用域

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
15
var 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
6
let 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
11
let fn = () => 2;
//等同于
let fn = function(){
return 2;
}

let fn = (num1,num2) => num1+num2
//等同于
let fn = function(num1,num2){
return num1+num2;
}

如果加上{},return不能省略的

1
2
3
4
5
6
7
8
9
10
11
//当不写{},且没有其他操作时,默认返回值
let fn = () => 2;
console.log(fn()) //2

//当加上{}时,return不可省略
let fn = () => {2};
console.log(fn()) //undefined

//{}里要写完整的代码
let fn = () => {return 2}
console.log(fn()) //2

如果箭头函数只有一行语句,且不需要返回值

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
19
function 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
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
27
28
29
30
//属性简写
let name = 'xiaoming';
let age = 20;

let obj = {
name,
age
}
//等同于
let obj = {
name:name,
age:age
}

//只要属性名和属性值变量同名即可



//方法简写
let obj = {
showName(){
alert('xiaoming');
}
}
//等同于
let obj = {
showName:function(){
alert('xiaoming');
}
}

属性名表达式

在ES5中,使用字面量方式定义对象(使用大括号),只能使用标识符定义属性名:

1
2
3
4
var obj = {
foo: true,
abc: 123
};

现在ES6允许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内:

1
2
3
4
5
6
7
8
let key = 'num';

let obj = {
[key]:123,
['na' + 'me']:'jhon'
}

console.log(obj); // {num: 123, name: "jhon"}

表达式还可以用于定义方法名:

1
2
3
4
5
6
7
let obj1 = {
['h' + 'ello'](){
console.log('hi');
}
}

obj1.hello(); //hi

注意,属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]:

1
2
3
4
5
6
const 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
9
let 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
2
3
4
5
6
7
8
9
10
//将上面例子改变一下
let o1 = {'a':1,'b':2};

let o2 = {'b':3,'c':4};

let o3 = {'c':5};

Object.assign(o1,o2,o3);

console.log(o1); //{a: 1, b: 3, c: 5}

拷贝

1
2
3
4
5
6
7
8
var obj1 = {
'a':1,
'b':2
}

var obj2 = Object.assign({},obj1);

console.log(obj2); //{a: 1, b: 2}

需要注意的是,Object.assign方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。

1
2
3
4
5
6
7
8
9
10
11
var obj1 = {
'a':{
'b':1
}
}

var obj2 = Object.assign({},obj1);

obj1.a.b = 2;

console.log(obj2.a.b); //2