浅尝ES6

Class和普通构造函数

class为es6的语法糖;

总的来说class的语法更接近面向对象,更加已读,对于后端开发来说更容易上手;

class底层原理还是prototype;

普通构造函数实现

1
2
3
4
5
6
7
8
9
10
function User(name, age) {
this.name = name;
this.age = age;
}
User.prototype.login = function() {
console.log('user is logining');
}

var user = new User();
user.login();

class实现

1
2
3
4
5
6
7
8
9
10
11
12
13
class User {
// 构造方法
constructor(name, age) {
this.name = name;
this.age = age;
}
// 类方法
login() {
console.log('user is logining');
}
}
var user = new User();
user.login();

继承

普通继承实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Animal() {
this.eat = function() {
console.log('eating');
}
}
function Dog() {
this.wang = function() {
console.log('wangwangwang');
}
}
// Dog继承Animal
Dog.prototype = new Animal();
var dog = new Dog();
dog.wang();
dog.eat();

class实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log('eating');
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
wang() {
console.log('wangwangwang');
}
}
var dog = new Dog('bog');
dog.wang();
dog.eat();

var与let作用域

let在es6中用来声明变量,用法类型与var

  • var的作用域为函数上下文或全局上下文;

  • let的作用域由最近的一对{}所限定,及只在局部有效;

  • var变量可以重复声明,但是let变量重复声明会报错(SyntaxError);

  • let适合在循环中声明变量;

变量的解构赋值

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

数组的解构赋值

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
// 老写法
// 为变量赋值,只能直接指定值
var a = 1;
var b = 2;
var c = 3;

// 解构赋值写法
// 从数组中提取值,按照对应位置,对变量赋值
var [a, b, c] = [1, 2, 3];

// 允许嵌套
// 这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值
let [foo, [[bar], baz]] = [1, [[2], 3]];

// 如果解构不成功,变量的值就等于undefined
var [foo] = [];
var [bar, foo] = [1];

// 不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组
let [x, y] = [1, 2, 3];

// 指定默认值
var [foo = true] = [];

// 默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [x = 1, y = x] = [];

对象的解构赋值

1
2
3
4
5
6
7
// 数组解构赋值是按照顺序,而对象解构赋值则要求变量必须与属性同名,若不一致则需要两边属性名一致
var { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
// 以上可以简写为
var { foo, bar } = { foo: "aaa", bar: "bbb" };

// 同样也可以指定默认值
var {x = 3} = {};

字符串的解构赋值

1
const [a, b, c, d, e] = 'hello';

函数参数的解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
function add([x, y]){
return x + y;
}
add([1, 2]); // 3

// 默认值
function move({x = 0, y = 0} = {}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]

变量的解构赋值用途

  1. 交换变量的值

    1
    [x, y] = [y, x];
  2. 从函数返回多个值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 返回一个数组
    function example() {
    return [1, 2, 3];
    }
    var [a, b, c] = example();

    // 返回一个对象
    function example() {
    return {
    foo: 1,
    bar: 2
    };
    }
    var { foo, bar } = example();
  3. 函数参数的定义

    1
    2
    3
    4
    5
    6
    7
    // 参数是一组有次序的值
    function f([x, y, z]) { ... }
    f([1, 2, 3]);

    // 参数是一组无次序的值
    function f({x, y, z}) { ... }
    f({z: 3, y: 2, x: 1});
  4. 提取JSON数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var jsonData = {
    id: 42,
    status: "OK",
    data: [867, 5309]
    };

    let { id, status, data: number } = jsonData;

    console.log(id, status, number);
  5. 函数参数的默认值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    jQuery.ajax = function (url, {
    async = true,
    beforeSend = function () {},
    cache = true,
    complete = function () {},
    crossDomain = false,
    global = true,
    // ... more config
    }) {
    // ... do stuff
    };
  6. 遍历Map结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var map = new Map();
    map.set('first', 'hello');
    map.set('second', 'world');

    for (let [key, value] of map) {
    console.log(key + " is " + value);
    }

    // 获取键名
    for (let [key] of map) {
    // ...
    }

    // 获取键值
    for (let [,value] of map) {
    // ...
    }
  7. 加载模块的指定方法

    1
    const { SourceMapConsumer, SourceNode } = require("source-map");

字符串的扩展

实用方法

  • includes():返回布尔值,表示是否找到了参数字符串;

  • startsWith():返回布尔值,表示参数字符串是否在源字符串的头部;

  • endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部;

  • repeat():方法返回一个新字符串,表示将原字符串重复n次,若n为小数则向下取整,若n为负数或报错;

  • padStart(),padEnd():字符串补全长度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'

    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'

    // 省略第二个参数,则会用空格补全长度
    'x'.padStart(4) // ' x'
    'x'.padEnd(4) // 'x '

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

模板字符串中嵌入变量,需要将变量名写在${}之中。

大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。

模板字符串之中还能调用函数。

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
// js写法
$('#result').append(
'There are <b>' + basket.count + '</b> ' +
'items in your basket, ' +
'<em>' + basket.onSale +
'</em> are on sale!'
);

// 模板字符串写法
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);

// 模板字符串嵌套
const data = [
{ first: '<Jane>', last: 'Bond' },
{ first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;

数组的扩展

  • Array.from():将类似数组的对象(array-like object)和可遍历(iterable)的对象转化为数组

    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
    let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
    };
    // ES6的写法
    let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

    // 常见的类似数组的对象是DOM操作返回的NodeList集合,以及函数内部的arguments对象
    // NodeList对象
    let ps = document.querySelectorAll('p');
    Array.from(ps).forEach(function (p) {
    console.log(p);
    });
    // arguments对象
    function foo() {
    var args = Array.from(arguments);
    // ...
    }

    // 值得提醒的是,扩展运算符(...)也可以将某些数据结构转为数组
    // arguments对象
    function foo() {
    var args = [...arguments];
    }
    // NodeList对象
    [...document.querySelectorAll('div')]
  • find()和findIndex():用于找出第一个符合条件的数组成员或下标

    1
    2
    3
    4
    [1, 5, 10, 15].find(function(value, index, arr) {
    return value > 9;
    }) // 10
    // find方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组
  • fill():填充数组

  • includes():法返回一个布尔值,表示某个数组是否包含给定的值

扩展运算符

扩展运算符(spread)是三个点(...),将一个数组转为用逗号分隔的参数序列

用于函数调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function push(array, ...items) {
array.push(...items);
}

function add(x, y) {
return x + y;
}

var numbers = [4, 38];
add(...numbers) // 42

// 扩展运算符与正常的函数参数可以结合使用,非常灵活
function f(v, w, x, y, z) { }
var args = [0, 1];
f(-1, ...args, 2, ...[3]);

替代数组的apply方法

1
2
3
4
5
6
7
8
// ES5的写法
Math.max.apply(null, [14, 3, 77])

// ES6的写法
Math.max(...[14, 3, 77])

// 等同于
Math.max(14, 3, 77);

扩展运算符的应用

  1. 合并数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // ES5
    [1, 2].concat(more)
    // ES6
    [1, 2, ...more]

    var arr1 = ['a', 'b'];
    var arr2 = ['c'];
    var arr3 = ['d', 'e'];

    // ES5的合并数组
    arr1.concat(arr2, arr3);
    // [ 'a', 'b', 'c', 'd', 'e' ]

    // ES6的合并数组
    [...arr1, ...arr2, ...arr3]
    // [ 'a', 'b', 'c', 'd', 'e' ]
  2. 与解构赋值结合

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const [first, ...rest] = [1, 2, 3, 4, 5];
    first // 1
    rest // [2, 3, 4, 5]

    const [first, ...rest] = [];
    first // undefined
    rest // []:

    const [first, ...rest] = ["foo"];
    first // "foo"
    rest // []
  3. 函数的返回值

    1
    2
    var dateFields = readDateFields(database);
    var d = new Date(...dateFields);
  4. 字符串

    1
    2
    3
    // 扩展运算符还可以将字符串转为真正的数组
    [...'hello']
    // [ "h", "e", "l", "l", "o" ]
  5. 实现了Iterator接口的对象

    1
    2
    3
    // 任何Iterator接口的对象,都可以用扩展运算符转为真正的数组
    var nodeList = document.querySelectorAll('div');
    var array = [...nodeList];
  6. Map和Set结构,Generator函数

    1
    2
    3
    4
    5
    6
    7
    let map = new Map([
    [1, 'one'],
    [2, 'two'],
    [3, 'three'],
    ]);

    let arr = [...map.keys()]; // [1, 2, 3]

箭头函数

ES6允许使用“箭头”(=>)定义函数。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var f = v => v;

// 上面的箭头函数等同于
var f = function(v) {
return v;
};

// 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
var f = () => 5;
// 等同于
var f = function () { return 5 };

// 如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回
var sum = (num1, num2) => { return num1 + num2; }

// 箭头函数可以与变量解构结合使用
const full = ({ first, last }) => first + ' ' + last;

使用注意点

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替
  • 不可以使用yield命令,因此箭头函数不能用作Generator函数

对象的拓展

Object.is()

它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

1
2
3
4
5
6
7
8
9
10
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

Object.assign()

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

类似于jQuery中的$.extend()方法。

1
2
3
4
5
6
7
var target = { a: 1, b: 1 };

var source1 = { b: 2, c: 2 };
var source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

常见用法

  • 为对象添加属性

    1
    2
    3
    4
    5
    class Point {
    constructor(x, y) {
    Object.assign(this, {x, y});
    }
    }
  • 为对象添加方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Object.assign(SomeClass.prototype, {
    someMethod(arg1, arg2) {
    ···
    },
    anotherMethod() {
    ···
    }
    });

    // 等同于下面的写法
    SomeClass.prototype.someMethod = function (arg1, arg2) {
    ···
    };
    SomeClass.prototype.anotherMethod = function () {
    ···
    };
  • 克隆对象

    1
    2
    3
    function clone(origin) {
    return Object.assign({}, origin);
    }
  • 合并多个对象

    1
    2
    const merge =
    (...sources) => Object.assign({}, ...sources);
  • 为属性指定默认值

    1
    2
    3
    4
    5
    6
    7
    8
    const DEFAULTS = {
    logLevel: 0,
    outputFormat: 'html'
    };

    function processContent(options) {
    options = Object.assign({}, DEFAULTS, options);
    }

属性的遍历

  1. for…in
  2. Object.keys(obj)
  3. Object.getOwnPropertyNames(obj)
  4. Object.getOwnPropertySymbols(obj)
  5. Reflect.ownKeys(obj)

浅尝ES6
https://blog.kedr.cc/posts/3657735712/
作者
zhuweitung
发布于
2021年5月16日
许可协议