ES6 小结(前端开发js技术进阶提升总结)


es6中有很多特性,使javascript语法更加丰满,总结一波常用的es6知识点。

1.变量声明const和let

在ES6之前,我们都是用var关键字声明变量。无论声明在何处,都会被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部)。这就是函数变量提升例如:

  1. function a() {

  2.    if(bool) {

  3.        var str // 变量提升

  4.        str = 'frontend'

  5.    } else {

  6.        //此处访问str 值为undefined

  7.        console.log(str)

  8.    }

  9. }

所以不用关心bool是否为true or false。实际上,无论如何str都会被创建声明。

而es6之后,我们通常用let和const来声明。let表示变量、const表示常量,let和const都是块级作用域。如何理解这个块级作用域?

  • 在一个函数内部

  • 在一个代码块内部

  • 通常来说{}大括号内的代码块即为let和const的作用域。

    1. function a() {

    2.    if(bool) {

    3.       let str = 'frontend

    4.    } else {

    5.        //str 在此处访问不到

    6.        console.log(str)

    7.    }

    8.  }

    let 的作用域是在它所在当前代码块,但不会被提升到当前函数的最顶部。

    const 声明的变量都会被认为是常量,表示它的值被设置完成后就不能再修改了。

    1.  const role = 'frontend'

    2.  role = 'backend' //再次赋值此时会报错

    如果const的是一个对象,对象所包含的值是可以被修改的。就是对象所指向的地址没有变就行。

    1.    const student = { name: 'cc' }

    2.    // 不报错

    3.    student.name = 'yy'

    4.    // 如果这样子就会报错了

    5.    student  = { name: 'yy' }

    常见面试题中:

    1. var funcs = []

    2.    for (var i = 0; i < 10; i++) {

    3.        funcs.push(function() { console.log(i) })

    4.    }

    5.    funcs.forEach(function(func) {

    6.        func()

    7.    })

    这样的面试题是大家常见,很多同学一看就知道输出 10 十次。

    但是如果我们想依次输出0到9呢?

    有两种解决方法。直接看一下代码。

    1.    // ES5利用闭包解决这个问题

    2.    var funcs = []

    3.    for (var i = 0; i < 10; i++) {

    4.        funcs.push(

    5.          (function(value) {

    6.            return function() {

    7.                console.log(value)

    8.            }

    9.        })(i)

    10.      )

    11.    }

    12.    funcs.forEach(function(func) {

    13.        func()

    14.    })

    1.    // es6解决

    2.    const funcs = []

    3.    for (let i = 0; i < 10; i++) {

    4.        funcs.push(function() {

    5.            console.log(i)

    6.        })

    7.    }

    8.    funcs.forEach(func => func())

    es6解决方案更加简洁方便。

    2.模板字符串

    es6模板字符简直是开发者的福音,解决了es5在字符串功能上的痛点。

    第一个用途,基本的字符串格式化。将表达式嵌入字符串中进行拼接。用${}来界定。

    1. //ES5

    2.    var name = 'frontend'

    3.    console.log('hello' + name)

    4.    //es6

    5.    const name = 'frontend'

    6.    console.log(`hello ${name}`)

    第二个用途,在ES5时我们通过反斜杠()来做多行字符串或者字符串一行行拼接。ES6反引号(``)直接搞定。

    1.    // ES5

    2.    var msg = "Hi

    3.    man!

    4.    "

    5.    // ES6

    6.    const template = `<div>

    7.        <span>hello world</span>

    8.    </div>`

    对于字符串ES6当然也提供了很多厉害也很有意思的方法。

    1.    // 1.includes:判断是否包含然后直接返回布尔值

    2.    const str = 'hahay'

    3.    console.log(str.includes('y')) // true


    4.    // 2.repeat: 获取字符串重复n次

    5.    const str = 'he'

    6.    console.log(str.repeat(3)) // 'hehehe'

    7.    //如果你带入小数, Math.floor(num) 来处理

    8.    // s.repeat(3.1) 或者 s.repeat(3.9) 都当做成 s.repeat(3) 来处理


    9.    // 3. startsWith 和 endsWith 判断是否以 给定文本 开始或者结束

    10.    const str =  'hello world!'

    11.    console.log(str.startsWith('hello')) // true

    12.    console.log(str.endsWith('!')) // true

    3.函数

    函数默认参数

    在ES5我们给函数定义参数默认值是怎么样?

    1.    function action(num) {

    2.        num = num || 200

    3.        //当传入num时,num为传入的值

    4.        //当没传入参数时,num即有了默认值200

    5.        return num

    6.    }

    但细心观察的同学们肯定会发现,num传入为0的时候就是false,但是我们实际的需求就是要拿到num = 0,此时num = 200 明显与我们的实际想要的效果明显不一样。

    ES6为参数提供了默认值。在定义函数时便初始化了这个参数,以便在参数没有被传递进去时使用。

    1.    function action(num = 200) {

    2.        console.log(num)

    3.    }

    4.    action(0) // 0

    5.    action() //200

    6.    action(300) //300

    箭头函数

    ES6很有意思的一部分就是函数的快捷写法。也就是箭头函数。

    箭头函数最直观的三个特点:

  • 不需要 function 关键字来创建函数

  • 省略 return 关键字

  • 继承当前上下文的 this 关键字

    1.    //例如:

    2.    [1,2,3].map(x => x + 1)


    3.    //等同于:

    4.    [1,2,3].map((function(x){

    5.        return x + 1

    6.    }).bind(this))

    说个小细节。

    当你的函数有且仅有一个参数的时候,是可以省略掉括号的。当你函数返回有且仅有一个表达式的时候可以省略{} 和 return。例如:

    1. var people = name => 'hello' + name

    2.  //参数name就没有括号

    作为参考:

    1.    var people = (name, age) => {

    2.        const fullName = 'hello' + name

    3.        return fullName

    4.    }

    5.    //如果缺少()或者{}就会报错

    来道笔试题:

    1.    // 请使用ES6重构以下代码

    2.    var calculate = function(x, y, z) {

    3.      if (typeof x != 'number') { x = 0 }

    4.      if (typeof y != 'number') { y = 6 }


    5.      var dwt = x % y

    6.      var result


    7.      if (dwt == z) { result = true }

    8.      if (dwt != z) { result = false }


    9.      return result

    10.    }

    1.  const calculate = (x, y, z) => {

    2.      x = typeof x !== 'number' ? 0 : x

    3.      y = typeof y !== 'number' ? 6 : y

    4.      return x % y === z

    5.    }

    4.拓展的对象功能

    对象初始化简写

    ES5我们对于对象都是以键值对的形式书写,是有可能出现键值对重名的。例如:

    1.    function people(name, age) {

    2.        return {

    3.            name: name,

    4.            age: age

    5.        };

    6.    }

    键值对重名,ES6可以简写如下:

    1.    function people(name, age) {

    2.        return {

    3.            name,

    4.            age

    5.        };

    6.    }

    ES6 同样改进了为对象字面量方法赋值的语法。ES5为对象添加方法:

    1.    const people = {

    2.        name: 'sa',

    3.        getName: function() {

    4.            console.log(this.name)

    5.        }

    6.    }

    ES6通过省略冒号与 function 关键字,将这个语法变得更简洁:

    1.    const people = {

    2.        name: 'sa',

    3.        getName () {

    4.            console.log(this.name)

    5.        }

    6.    }

    ES6 对象提供了 Object.assign() 这个方法来实现浅复制。

    Object.assign() 可以把任意多个源对象自身可枚举的属性拷贝给目标对象,然后返回目标对象。第一参数即为目标对象。在实际项目中,我们为了不改变源对象。一般会把目标对象传为{}。

    1.    const objA = { name: 'cc', age: 18 }

    2.    const objB = { address: 'beijing' }

    3.    const objC = {} // 这个为目标对象

    4.    const obj = Object.assign(objC, objA, objB)


    5.    // 我们将 objA objB objC obj 分别输出看看

    6.    console.log(objA)   // { name: 'cc', age: 18 }

    7.    console.log(objB) // { address: 'beijing' }

    8.    console.log(objC) // { name: 'cc', age: 18, address: 'beijing' }

    9.    console.log(obj) // { name: 'cc', age: 18, address: 'beijing' }


    10.    // 是的,目标对象ObjC的值被改变了。

    11.    // so,如果objC也是你的一个源对象的话。请在objC前面填在一个目标对象{}

    12.    Object.assign({}, objC, objA, objB)

    5.更方便的数据访问--解构

    数组和对象是JS中最常用也是最重要表示形式。为了简化提取信息,ES6新增了解构,这是将一个数据结构分解为更小的部分的过程。

    ES5我们提取对象中的信息形式如下:

    1. const people = {

    2.        name: 'lux',

    3.        age: 20

    4.    }

    5.    const name = people.name

    6.    const age = people.age

    7.    console.log(name + ' --- ' + age)

    是不是觉得很熟悉,没错,在ES6之前我们就是这样获取对象信息的,一个一个获取。现在,解构能让我们从对象或者数组里取出数据存为变量,例如:

    1.    //对象

    2.    const people = {

    3.        name: 'sa',

    4.        age: 20

    5.    }

    6.    const { name, age } = people

    7.    console.log(`${name} --- ${age}`)

    8.    //数组

    9.    const color = ['red', 'blue']

    10.    const [first, second] = color

    11.    console.log(first) //'red'

    12.    console.log(second) //'blue'

    面试题:

    1.    // 请使用 ES6 重构一下代码


    2.    // 第一题

    3.    var jsonParse = require('body-parser').jsonParse


    4.    // 第二题

    5.    var body = request.body

    6.    var username = body.username

    7.    var password = body.password

    1.    // 1.

    2.    import { jsonParse } from 'body-parser'

    3.    // 2.

    4.    const { body, body: { username, password } } = request

    6.Spread Operator 展开运算符

    ES6中另外一个好玩的特性就是Spread Operator 也是三个点儿...接下来就展示一下它的用途。

    组装对象或者数组:

    1.    //数组

    2.    const color = ['red', 'yellow']

    3.    const colorful = [...color, 'green', 'pink']

    4.    console.log(colorful) //[red, yellow, green, pink]


    5.    //对象

    6.    const alp = { fist: 'a', second: 'b'}

    7.    const alphabets = { ...alp, third: 'c' }

    8.    console.log(alphabets) //{ "fist": "a", "second": "b", "third": "c" }

    有时候我们想获取数组或者对象除了前几项或者除了某几项的其他项。

    1.    //数组

    2.    const number = [1,2,3,4,5]

    3.    const [first, ...rest] = number

    4.    console.log(rest) //2,3,4,5

    5.    //对象

    6.    const user = {

    7.        username: 'lux',

    8.        gender: 'female',

    9.        age: 19,

    10.        address: 'peking'

    11.    }

    12.    const { username, ...rest } = user

    13.    console.log(rest) //{"address": "peking", "age": 19, "gender": "female" }

    对于 Object 而言,还可以用于组合成新的 Object 。(ES2017 stage-2 proposal) 当然如果有重复的属性名,右边覆盖左边。

    1.    const first = {

    2.        a: 1,

    3.        b: 2,

    4.        c: 6,

    5.    }

    6.    const second = {

    7.        c: 3,

    8.        d: 4

    9.    }

    10.    const total = { ...first, ...second }

    11.    console.log(total) // { a: 1, b: 2, c: 3, d: 4 }

    7.import 和 export

    import导入模块、export导出模块:

    1. //全部导入

    2. import people from './example'


    3. //有一种特殊情况,即允许你将整个模块当作单一对象进行导入

    4. //该模块的所有导出都会作为对象的属性存在

    5. import * as example from "./example.js"

    6. console.log(example.name)

    7. console.log(example.age)

    8. console.log(example.getName())


    9. //导入部分

    10. import {name, age} from './example'


    11. // 导出默认, 有且只有一个默认

    12. export default App


    13. // 部分导出

    14. export class App extend Component {};

    导入的时候有没有大括号的区别是什么。下面是总结:

  • 当用export default people导出时,就用 import people 导入(不带大括号)。

  • 一个文件里,有且只能有一个export default。但可以有多个export。

  • 当用export name 时,就用 import{name} 导入(记得带上大括号)。

  • 当一个文件里,既有一个export default people, 又有多个export name 或者 export age时,导入就用 importpeople,{name,age}

  • 当一个文件里出现n多个 export 导出很多模块,导入时除了一个一个导入,也可以用 import*asexample

  • 8. Promise

    在promise之前代码过多的回调或者嵌套,可读性差、耦合度高、扩展性低。通过Promise机制,扁平化的代码机构,大大提高了代码可读性;用同步编程的方式来编写异步代码,保存线性的代码逻辑,极大的降低了代码耦合性而提高了程序的可扩展性。

    说白了就是用同步的方式去写异步代码。

    发起异步请求:

    1.    fetch('/api/todos')

    2.      .then(res => res.json())

    3.      .then(data => ({ data }))

    4.      .catch(err => ({ err }));

    面试题:

    1.    setTimeout(function() {

    2.      console.log(1)

    3.    }, 0);

    4.    new Promise(function executor(resolve) {

    5.      console.log(2);

    6.      for( var i=0 ; i<10000 ; i++ ) {

    7.        i == 9999 && resolve();

    8.      }

    9.      console.log(3);

    10.    }).then(function() {

    11.      console.log(4);

    12.    });

    13.    console.log(5);

    9.Generators

    生成器( generator)是能返回一个迭代器的函数。生成器函数也是一种函数,最直观的表现就是比普通的function多了个星号*,在其函数体内可以使用yield关键字,有意思的是函数会在每个yield后暂停。

    这里生活中有一个比较形象的例子。咱们到银行办理业务时候都得向大厅的机器取一张排队号。你拿到你的排队号,机器并不会自动为你再出下一张票。也就是说取票机“暂停”住了,直到下一个人再次唤起才会继续吐票。

    OK。说说迭代器。当你调用一个generator时,它将返回一个迭代器对象。这个迭代器对象拥有一个叫做next的方法来帮助你重启generator函数并得到下一个值。next方法不仅返回值,它返回的对象具有两个属性:done和value。value是你获得的值,done用来表明你的generator是否已经停止提供值。继续用刚刚取票的例子,每张排队号就是这里的value,打印票的纸是否用完就这是这里的done。

    1.    // 生成器

    2.    function *createIterator() {

    3.        yield 1;

    4.        yield 2;

    5.        yield 3;

    6.    }


    7.    // 生成器能像正规函数那样被调用,但会返回一个迭代器

    8.    let iterator = createIterator();


    9.    console.log(iterator.next().value); // 1

    10.    console.log(iterator.next().value); // 2

    11.    console.log(iterator.next().value); // 3

    那生成器和迭代器又有什么用处呢?

    围绕着生成器的许多兴奋点都与异步编程直接相关。异步调用对于我们来说是很困难的事,我们的函数并不会等待异步调用完再执行,你可能会想到用回调函数,(当然还有其他方案比如Promise比如Async/await)。

    生成器可以让我们的代码进行等待。就不用嵌套的回调函数。使用generator可以确保当异步调用在我们的generator函数运行一下行代码之前完成时暂停函数的执行。

    那么问题来了,咱们也不能手动一直调用next()方法,你需要一个能够调用生成器并启动迭代器的方法。就像这样子的:

    1.    function run(taskDef) { //taskDef即一个生成器函数


    2.        // 创建迭代器,让它在别处可用

    3.        let task = taskDef();


    4.        // 启动任务

    5.        let result = task.next();


    6.        // 递归使用函数来保持对 next() 的调用

    7.        function step() {


    8.            // 如果还有更多要做的

    9.            if (!result.done) {

    10.                result = task.next();

    11.                step();

    12.            }

    13.        }


    14.        // 开始处理过程

    15.        step();


    16.    }

    生成器与迭代器最有趣、最令人激动的方面,或许就是可创建外观清晰的异步操作代码。你不必到处使用回调函数,而是可以建立貌似同步的代码,但实际上却使用 yield 来等待异步操作结束。

    10.async 函数

    es6引入了 async 函数,使得异步操作变得更加方便。

    async 函数是什么?一句话,它就是 Generator 函数的语法糖。

    1. function timeout(ms) {

    2.  return new Promise((resolve) => {

    3.    setTimeout(resolve, ms);

    4.  });

    5. }


    6. async function asyncPrint(value, ms) {

    7.  await timeout(ms);

    8.  console.log(value);

    9. }


    10. asyncPrint('hello world', 50);

    一比较就会发现,async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。

    async函数对 Generator 函数的改进,体现在以下四点:

  • 内置执行器

  • 更好的语义

  • 更广的适用性

  • 返回值是 Promise

  • 11.Class基本语法

    JavaScript 语言中,生成实例对象的传统方法是通过构造函数:

    1. function Point(x, y) {

    2.  this.x = x;

    3.  this.y = y;

    4. }


    5. Point.prototype.toString = function () {

    6.  return '(' + this.x + ', ' + this.y + ')';

    7. };


    8. var p = new Point(1, 2);

    es6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

    基本上,es6 的%(red)[class]可以看作只是一个语法糖,它的绝大部分功能,es5 都可以做到,新的%(red)[class]写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用 es6 的%(red)[class]改写,就是下面这样。

    1. //定义类

    2. class Point {

    3.  constructor(x, y) {

    4.    this.x = x;

    5.    this.y = y;

    6.  }


    7.  toString() {

    8.    return '(' + this.x + ', ' + this.y + ')';

    9.  }

    10. }

    上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,es5 的构造函数Point,对应 es6 的Point类的构造方法。

    Point类除了构造方法,还定义了一个toString方法。注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。

    es6 的类,完全可以看作构造函数的另一种写法。


    源自:http://forum.bestvist.com/topic/133/小结

    声明:文章著作权归作者所有,如有侵权,请联系小编删除。


    ©著作权归作者所有,转载或内容合作请联系作者
    • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
      沈念sama阅读 212,332评论 6 493
    • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
      沈念sama阅读 90,508评论 3 385
    • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
      开封第一讲书人阅读 157,812评论 0 348
    • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
      开封第一讲书人阅读 56,607评论 1 284
    • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
      茶点故事阅读 65,728评论 6 386
    • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
      开封第一讲书人阅读 49,919评论 1 290
    • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
      沈念sama阅读 39,071评论 3 410
    • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
      开封第一讲书人阅读 37,802评论 0 268
    • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
      沈念sama阅读 44,256评论 1 303
    • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
      茶点故事阅读 36,576评论 2 327
    • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
      茶点故事阅读 38,712评论 1 341
    • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
      沈念sama阅读 34,389评论 4 332
    • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
      茶点故事阅读 40,032评论 3 316
    • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
      开封第一讲书人阅读 30,798评论 0 21
    • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
      开封第一讲书人阅读 32,026评论 1 266
    • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
      沈念sama阅读 46,473评论 2 360
    • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
      茶点故事阅读 43,606评论 2 350

    推荐阅读更多精彩内容

    • { "Unterminated string literal.": "未终止的字符串文本。", "Identifi...
      Elbert_Z阅读 10,808评论 0 2
    • 原文链接 es6中有很多特性,使javascript语法更加丰满,总结一波常用的es6知识点。 1.变量声明con...
      bestvist阅读 583评论 0 22
    • 以下内容是我在学习和研究ES6时,对ES6的特性、重点和注意事项的提取、精练和总结,可以做为ES6特性的字典;在本...
      科研者阅读 3,121评论 2 9
    • "Unterminated string literal.": "未终止的字符串文本。", "Identifier...
      两个心阅读 8,351评论 0 4
    • 文/古尔浪洼 你可能还没有过工作的经历,是个刚刚毕业的应届生;你也可能已经参加过工作,有过面试与工作的经验;或者你...
      古尔浪洼阅读 31,875评论 14 109