zoukankan      html  css  js  c++  java
  • ES6的日常一些功能

    1、前注

    关于es6的详细说明,可以参照我的系列文章es6 从入门到熟练,或者阮一峰的ECMAScript 6 入门

    我的系列文章,是在阮一峰的基础上,增加了更多适合初中级开发者的内容(包括大量的示例代码和解释),以降低学习难度,丰富说明。

    本文是对es6整体的回顾,结合我的实际开发经验,对es6的一个小结。

    为了精炼内容,es6里不常用的内容已经去掉,而对常用、重要的es6知识,附上简单的代码说明,并另附有详细说明的博文链接,方便初中级开发者理解。

    2、开发环境

    关键字:IE9、Babel、Babel的垫片、脚手架

    首先,使用es6的前提是最低IE9,如果你需要兼容IE8,建议放弃es6,专心使用神器jQuery。

    其次,如果需要使用es6来编写,那么你需要Babel转码器用于将你的es6代码转换为es5代码,用于兼容只能使用es5的环境。否则对于只能运行es5的环境(例如IE9),是无法运行es6代码的。

    第三,由于Babel在默认情况下,并不是全部转换的,如以下说明:

    Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。

    因此,我们需要垫片,一般情况下可以用babel-polyfill,也可以用babel-runtime,这两个有所差异。

    babel-polyfill会污染全局对象,即会对例如Object这样的对象添加方法,而babel-runtime只会转换es6语法的代码,但如果你需要调用Object.assign这样的方法,那就不行了。

    由于细节很多,因此这里给几个参考链接吧:

    Babel 全家桶

    babel的polyfill和runtime的区别

    看完以上两个,可能会觉得应该同时使用这两个,然而并不需要,看下面这个链接:

    transform-runtime 会自动应用 polyfill,即便没有使用 babel-polyfillconanliu17 Dec 2016提交的issues。

    如果你使用的Vue.js,那么可以直接fork我的脚手架,然后当做自己的脚手架使用。

    附脚手架链接:vue-scaffold,如果可以,给个star喔~~

    如果你用的不是Vue.js,那么可以去搜一下你所使用的框架的脚手架,然后拿来使用。如果找不到,可以找使用带脚手架的该框架项目,然后down下来,删除对方的项目只取壳来用即可。(如果有许可,记得阅读一下许可看能不能这么干)

    3、let和const

    既然有let和const了,那么推荐优先使用这两个。

    一般情况下,let可以直接替代var,对于常量,可以用const。

    这不是必须的,但用这2个可以帮你规范写代码的习惯,所以还是强烈推荐的。

    比较蛋疼的是,用webtorm,let有时候不会高亮,只有var和const是高亮的。这个可能是用的风格的问题,我也不太确定。解决方案我自己是没找到,凑合用吧。

    另外,let和var之间的一个重要区别是变量提升,所以如果你写代码不太规范的话,可能会报错,好好检查一下吧。

    另外,阮一峰推荐将函数设置为常量,就像这样子:

    const add = function (a, b) {
        return a + b
    }
    • 1
    • 2
    • 3

    我觉得挺有道理的,推荐。

    4、字符串

    既然用es6,当然要用反引号这个高大上的东西了。

    详细用法推荐我自己的博客:ECMAScript 6(7)模板字符串

    最基本的用法,可以直接用反引号替代普通的引号(单引号和双引号)

    例如:

    let a = 'ab'
    // 可以直接用以下替换
    let a = `ab`
    • 1
    • 2
    • 3

    而且一般情况下,简单需求不用再拼接字符串了~(另外,反引号也可以像普通字符串那样拼接)

    如:

    let str = '20004604';
    let html = 'my QQ is ' + str;
    
    //用以下替换
    let str = '20004604';
    let html = `my QQ is ${str}`;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    简单暴力省事。

    5、解构赋值

    最大的好处是简化了写法,如代码:

    let obj = {
        a: 1,
        b: 2
    }
    
    //old
    let a = obj.a;
    let b = obj.b;
    
    // es6
    let {a, b} = obj
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    除了对象之外,还有数组也可以解构赋值,别忘了。

    6、对象

    es6的对象,比早期版本的写起来舒服很多。

    例如:

    1. 对象属性是函数的时候可以简写;
    2. setter和getter的简写;
    3. 通过Object.assign()来合并对象,实现继承或添加属性效果;
    4. 可以用属性名表达式;
    5. 可以用变量名只要作为对象的属性名,并且变量的值可以自动成为对象该属性名的值;

    列一些常见写法:

    let obj = {
        // 对象属性是函数的时候可以简写
        a(){
            console.log('对象属性是函数的时候可以简写')
        },
        // setter和getter的简写;
        get b() {
            return this._b
        },
        set b(val) {
            this._b = val
        }
    }
    
    
    let c = '添加了一个c'
    // 通过``Object.assign()``来合并对象,实现继承或添加属性效果
    // 可以用变量名只要作为对象的属性名,并且变量的值可以自动成为对象该属性名的值
    Object.assign(obj, {
        c
    })
    
    // 可以用属性名表达式
    let d = "abcd"
    obj[d.replace(/abc/, '')] = '属性名表达式'
    • 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

    7、数组

    最常用的就两个:

    1. 扩展运算符...
    2. 将类数组的转为数组的Array.from()

    如代码:

    function getArgs() {
        let foo = [...arguments]
        console.log(foo)
        let bar = Array.from(arguments)
        console.log(bar)
    }
    getArgs(1, 2, 3)
    // [1, 2, 3]
    // [1, 2, 3]
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    需要注意的一个特性:

    1. es5在面对,通过Array(5)这样生成带空位的数组时,处理他的时候会跳过空位数组的空位
    2. es6在同样情况下,因为使用遍历器接口,所以会进行处理(视为undefined),而不是跳过;

    8、函数

    函数常用特性有以下几个:

    1. 箭头函数:特点是this永远指向声明时的父级作用域,写起来比普通函数简单;
    2. bind:可以给函数绑定this,并将这个绑定后的函数返回(不影响原函数);
    3. rest函数:即函数参数使用例如function test(..args){}这样的,这个返回的是一个数组,而不是类数组。
    4. 参数默认值:一般带默认值的参数,放在参数列表的后面。
    function test(a, b = 3) {
        console.log(a, b)
        console.log(this)
    }
    test.bind('Is this')(1)
    // 1 3
    // Is this
    
    function test2(...args) {
        console.log(args.length)
    }
    test2(1, 2, 3, 4, 5)
    // 5
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    9、Set和Map

    Set结构最大的特点是去重,Map结构最大的特点是kv结构。

    Set:

    Set和数组类似,可以存储元素,但是Set不能存储相同的值。

    非引用类型变量来说,就是值相等;对于引用类型变量来说,指地址相等(而不是值相等)。详细情况请点击Set类型和WeakSet查看。

    至于去重,一般是对数组使用。先作为参数生成一个Set类型变量,再利用扩展运算符变回数组,去重完成,完美。

    利用扩展运算符,调用Set的迭代器接口

    // 去重
    let foo = new Set([1, 2, 3, 3, 3])
    console.log([...foo]);  // [1, 2, 3]
    • 1
    • 2
    • 3

    Map:

    Map结构和对象非常类似,不过最大的区别在于,Map结构可以用其他类型作为key,例如数组、对象等。

    Map可以参照这篇博客Map和WeakMap

    示例代码:

    let zhang = {
        firstName: "王"
    }
    let property = {
        gender: "男"
    }
    let foo = new Map()
    foo.set(zhang, property)
    foo.has(zhang)  // true
    foo.get(zhang)  // {gender: "男"}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    10、Promise

    Promise是es6的精华之一,他非常适用于异步处理。

    Promise对象在使用的时候,分为两部分,第一部分是new Promise这一步,第二部分是对返回的Promise实例进行处理的内容。

    因为是通过执行resolvereject来改变Promise的状态,从而决定执行then的时机的(类似回调函数),以及执行的哪一个。因此写起来和回调函数相近,但是可以连写,避免回调地狱的情况。

    关于Promise的详细介绍请阅读Promise(1)基础知识及之后三篇博客

    如示例代码(对比普通ajax和promise)(另注:为了方便理解,仿jQuery的写法,并且没有用jQuery的$.ajax().then()这种写法)

    // 模拟ajax
    function ajax (options) {
        setTimeout(function () {
            options.success(options.url)
        }, 1000)
    }
    
    // old
    let foo = function (callback) {
        ajax({
            url: "/1",
            success: function (result) {
                callback(result)
            }
        })
    }
    let foo2 = function (result) {
        console.log(result)
        return function (callback) {
            ajax({
                url: "/2",
                success: function (val) {
                    callback(val)
                }
            })
        }
    }
    // 核心,调用的时候如果是连续请求的话,基本要写成回调地狱了
    foo(function (result) {
        foo2(result)(function (val) {
            console.log(val)
        })
    })
    
    // Promise
    let bar = function () {
        return new Promise((resolve, reject) => {
            ajax({
                url: "/1",
                success: function (result) {
                    resolve(result)
                }
            })
        })
    }
    let bar2 = function (result) {
        console.log(result)
        return new Promise((resolve, reject) => {
            ajax({
                url: "/2",
                success: function (val) {
                    resolve(val)
                }
            })
        })
    }
    // 核心,then连写即可
    bar().then(function (result) {
        return bar2(result)
    }).then(function (result) {
        console.log(result)
    })
    • 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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    显然,then连写比回调函数的写法要方便一些。

    如果面对的是特殊需求,比如是多个ajax请求全部完成后,再执行执行函数,那么Promise的优势会更大一些,而非Promise写法要麻烦很多。

    甚至如果要对错误进行处理,那么Promise写法会更方便。

    不过这里只是小结,就不细说了。

    11、class

    class是好东西。

    有了class后,写构造函数、写类的继承的难度,下降了很多很多。

    先附我的博文class(1)基本概念,以及之后5篇博文。

    由于很简单,给一个示例大约就能理解这个是怎么用的:

    class Foo {
        constructor () {
            console.log('this is constructor')
            this.defaultValue = '变量要在构造函数里赋值,而不能直接声明'
        }
    
        log () {
            console.log('log')
        }
    }
    
    let foo = new Foo() // this is constructor
    foo.log()   // log
    foo.defaultValue   // "变量要在构造函数里赋值,而不能直接声明"
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    12、es6模块

    es6的模块不同于以往的CommonJS(node用,服务器环境),AMD(RequireJS的规范,浏览器环境,依赖前置)、CMD(SeaJS定义的规范,浏览器环境,依赖就近)。

    他的特点有两个:

    1. 编译时加载,因此可以做静态优化;
    2. 模块的引用进来的,都是值的引用,而非值的拷贝。

    缺点是:

    1. 浏览器环境下不支持,node环境下支持的也比较差;
    2. 必须考babel转码后才可以正常使用,因此对某些符合规范的特性支持的不是很好;

    详细说明阅读这篇博客:es6的import和export,另外三个规范阅读这篇博客AMD、CMD、CommonJS

    基本使用方式如示例代码:

    // foo.js
    let foo = 'foo'
    export default foo
    
    // bar.js
    import foo from 'foo'
    console.log(foo)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    13、async函数

    这个并不是es6的,而是es2017(又称es8)的内容。

    可以认为async函数是Generator函数的语法糖,详细说明参照这篇博客:async函数

    他的前置知识比较多,包括Iterator遍历器、Generator状态机、Thunk函数(自动执行Generator 函数)。

    简单的说,假如有多个异步请求,你需要让这些起步请求依次执行,例如在执行完前一个之后,再执行后一个。那么你就需要async函数了。

    async函数可以让你写这种请求如同写同步函数一样简单(对比【10】中的Promise更简单)。

    以下示例是基于【10】中的代码,在最后一步执行的时候,改用async函数来完成

    // 模拟ajax
    function ajax (options) {
        setTimeout(function () {
            options.success(options.url)
        }, 1000)
    }
    
    // Promise
    let bar = function () {
        return new Promise((resolve, reject) => {
            ajax({
                url: "/1",
                success: function (result) {
                    resolve(result)
                }
            })
        })
    }
    let bar2 = function (result) {
        console.log(result)
        return new Promise((resolve, reject) => {
            ajax({
                url: "/2",
                success: function (val) {
                    resolve(val)
                }
            })
        })
    }
    
    async function foo () {
        let result1 = await bar()
        let result2 = await bar2(result1)
        return result2
    }
    
    foo().then(result => {
        console.log(result)
    })
    • 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
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    可以发现,async让连续异步调用像写同步函数一样简单。

    14、ESLint

    规范化开发,建议还是用ESLint来帮忙检查吧。不会这个怎么行?

    ESLint是一个语法规则和代码风格的检查工具,可以用来保证写出语法正确、风格统一的代码。

    这里直接给一个阮一峰写的文章,等以后我再单独补一篇详细用法的博客。

    ESLint的使用

    15、小结

    es6常用内容基本就以上13点。

    虽然es6实际包括了很多知识,例如:

    1. string方面增加了对utf16字符的更好的支持;
    2. number方面增加了对最大值、最小值、以及合理误差误差值的处理等;
    3. Symbol产生唯一变量;
    4. Proxy的代理;
    5. 遍历器,状态机等等。

    但实际常用的就以上这些,如果只是日常使用的话,熟悉以上内容足够了。

    但若要做的更好,那么应该深入学习,es6新增的很多内容,是将传统后端语言的一些很好的思想,搬到JavaScript来,让js规范化。

    对于专精于前端的同学,学习es6的过程中,可以学习到这些来自于其他语言的精华,因此建议至少完整的看一遍,勿要只满足于常用的这些API。

  • 相关阅读:
    phpcs
    asp.net之cookie
    ajax技术
    union、except和intersect查询
    外连接查询
    对查询结果分组
    聚合函数查询
    数据库的约束
    数据库备份
    fusionCharts
  • 原文地址:https://www.cnblogs.com/mrnut/p/8658928.html
Copyright © 2011-2022 走看看