关于javascript:面试题之ES6的新特性详细

41次阅读

共计 5998 个字符,预计需要花费 15 分钟才能阅读完成。

ES6 新增的内容比拟多,而且开发当中也是经常会用到,有了各种 babel 的转换,市面上大在少数公司都在用 ES6 语法来开发。

JavaScript传说中是由网景公司的 Brendan Eich 大神在 10 天内设计实现的。抛开短时间设计一门编程语言这个话题不说,任何一门语言都不是 100% 完满的(php….)。

JS当然也有它的不足之处,比如说顶层对象的属性与全局变量的关系,而 ES6 办法当中的 const let modules 等都是试图在肯定水平上扭转 JS 历史遗留的问题,从而使其更加合理化。

因而,在学习一门语言的同时,咱们多点注意这门语言的历史及其设计的目标,能够帮忙咱们更加粗浅的了解这门语言,而不是一味的死记 API。

ES6 的学习当然是首推 阮一峰 老师的《ES6 规范入门》一书。上面也是对这本书的集体浏览总结。

先来张搬砖图:

1. const 和 let

let: 申明在代码块内无效的变量。

特点:

1. 在存在变理晋升(不能在变量申明之前应用)2. let 的暂时性死区:其实与 1 差不多,只有在块作用域有申明,就不能在本作用域申明前用主个变量。3. 不容许反复申明。

const: 申明一个只读的常量

特点:

1. 一但申明,这个值不能被扭转(对于援用类型,是援用的地址不能被扭转)2. 申明时必须赋值

面试中常会问到 var let const 三都的区别,答复的时候重视各自的特点,其实 const let 就是补救 var 的各种毛病,两都的特点就是 var 的毛病。

工作中申明变量多用 const 和 let

其中当申明的变量为援用类型如 Array,如果没有间接更改援用的地址,能够应用 const

2. 解构赋值

什么是解构赋值?

依照肯定模式从数组或对象中提取值,而后对变量进行赋值(先提取,再赋值)

数组:

let [a, b] = [1, 2]
// 以下的后果为左边数剩下的值所组成的数组
let [c, d ,...e] = [1, 2, 3, 4]
// 有默认值的写法
let [f = 100] = []  // f = 100
// 其中 String 也被视为类数组
let [a, b] = 'abcd' // a = a; b = b

对象:

变理名要与对象的属性名一样才能够:

let {foo} = {foo: 1, bar: 2} // foo = 1
// 重新命名(前面那个才是新变量)let {foo: newFoo} = {foo: 1, bar: 2} // newFoo = 1

理论应用:

  1. 替换两个变量的值

    [x, y] = [y, x]
  2. 函数的封装

    function fn({x, y} = {}) {console.log(x, y)
    }

    其中,函数参数为一个对象,不会像 (x, y) 的模式这样固定参数的程序,而 {} = {} 前面又赋一个空的对象就是为了在调用 fn 时不传参数而不会抛出错误导至程序停止

  3. 函数返回值的解构

    函数返回多个值

    // 有秩序的
    function foo() {return [a, b, c]
    }
    const [a, b, c] = foo()
    // 无次序的
    function foo() {return { a, b, c}
    }
    const {b, a, c} = foo()

3. 模板字符串

const h = 'hello'
`${h} word`

特点:

​ 能够换行,然而所有的空格和换行会被保留。

${}中能够应用任意的 javaScript 表白试、运算、援用对象属性、函数调用等。后果是其返回值。

4. 函数的扩大

  1. 函数的默认值

    function m(x = 1) {}
  2. rest 参数(用于获取函数的多余参数)

    function a(...values) {// value 是一个数组,第个元素是传入的各个参数}
  3. 函头函数

    特点:

    1. 函数体内的 this = 定义时所在的对像
    2. 不能够当作构造函数(不能用 new)
    3. 不能够用 arguments 对像,能够用 rest
    4. 不能够用 yield 命令(不能用作 Generator 函数)

    阮老师的书中这一章讲到了无关尾调用,尾递归的内容,值得一看。

5. 数组的扩大

  1. 扩大运算符。

    1. 用于代替数组的apply

      call apply bind 的区别:
      用于扭转 this 的指向,第一个参数为 this 指向的对像,前面的参数是作为函数的参数。
      区加在于:call apply 会即调用,而 bind 是生成一个等调用的函数。call bind 参数是一个个用逗号列举,而 apply 是传入一个数组。

      fn.apply(null, [1, 2, 3])
      fn.call(null, 1, 2, 3)
      fn.bind(null, 1, 2, 3)()
      // 指最大值
      Math.max(...[3,4,5,62,8])
    2. 合并数组

      // ES5
      [1, 2].concat(3)
      // ES6
      [1, 2, ...[3]]
    3. 新增的办法

      1. Array.from()将类数组转为数组
      • 可遍历的对象(iterable)(Set, Map)
      • 相似数组的对
      {'0': 'a', '1': 'b'}
      1. 实例的办法
      • find() findIndex()找出第一个符合条件的成页 / 下标(地位)
      • entries() keys() values() 用于遍历数组。(配合 for…of)
      • includes() 是否存在指定无素(返回布尔值)

5. 对象的扩大

  1. 属性的简写:

    let a = 100
    {a} 
    // 等同于
    {a: 100}

    办法名同样能够简写,vue 中就经常用这种写法:

    export default {
        name: 'VueComp', 
        data() {}, 
        create() {},
    }
    // 等同于
    export default {
        name: 'VueComp',
        data: function() {}, 
        create: function() {},
    }
  2. 属性名可心应用表达式:

    
    let foo = 'foo'
    
    [foo]: 'fooValue'
}

```
  1. 新增一些办法:

    • Object.is()

      • Object.assign()
      • 对像的一些遍历:

        Object.keys(), Object.values(), Object.entries()

        for(let key of Object.keys(obj)) {}
        for(let value of Object.values(obj)) {}
        for(let [key,value] of Object.entries(obj)){}
      • 扩大运算符(罕用)(es2017 新增,在 webpack 中要另外的 babel 转换)

## 6. Symbol

javascript 又新增的一种数据类型(第七种,另外 6 种为:UndefinedNullBooleanStringNumberObject)

注:symbol 作为对象的属性名时不会被 for...in,for...of,Object.keys() 辨认;能够改用 Reflect.ownkeys 办法.

## 7. Set、Map

Set 和 map 是 ES6 新增的数据结构。

  • Set

    特点:1. 相似数组,但其成员是惟一的。

      2. 是一个构造函数。
 用法:​    数组去重:```javascript
 [...new Set([1,1,1,2,3,4,3])]
 Array.from(new Set([1,1,1,2,3,4,3]))
 ```
  • Map

    特点:

    1. 为了解决 javascript 的对象只能用了符串作为键的问题。
 用法:(应用实例的 set,get,delete 办法增,查,删)```javascript
 const m = new Map()
 const obj = {a: 'aa'}
 m.set(obj, 'obj as key')
 m.get(obj) // 'obj as key'
 m.delete(obj)
 ```

 也能够在 new 时承受一个数组

 ```javascript
 const obj = {a: 'aa'}
 const m = new Map([['name': 'ym'],
     [obj, { b: 'bbbb'}]
 ])
 ```

 > 这段时间有一个很火的文章讲如何应用 map 组构来优化长长的 if..else 的

8. Promise

是异步编程的一种解决方案。

特点:

  1. 状态不受外界影响(有三种状态:padding, fulfilled,redected)
  2. 一旦状态扭转就不会再变。

用法:

const p = new Promise((resolve, reject) => {setTimeout(() => {resolve()
    }, 1000)
}).then(res => {})
.catch(err => {})

注:then 办法有两个参数,第一个是胜利的回调,第二个为失败的回调,即:

.then(res =>{}, err => {})

然而最好用 catch 办法,因为 catch 办法会捕捉 then 里的谬误,then 里有谬误程序不会停止。

Promise.all()

将一组 promise 再包装成一个 promise

var pa = Promise.all([p1, p2, p3])

特点:

  1. 当所有都 fulfilledj 时,promise.all 才 fulfilled
  2. 当只有一个 rejected 时,promise.all 就会 rejected

Iterator 和 for…of

Iterator 的 3 个作用:

  1. 为各种数据提供对立的,简便的拜访接口
  2. 使数据结构的成员能按某种秩序排列
  3. 次要供 for…of 用

原生有 iterator 的数据结构:

Array, Map, Set, String, TypeArray, argumentsNodeList

(object 是没有的)

for…of 与其余循环的比拟

  1. for 循环写法比拟麻烦
  2. 数组的 forEach: 无奈用 break;return 跳出循环。
  3. For…in

    • 数组的键名是数字,而 for…in 以字符串作为键名(也就是用 for…in 循环数组,其键名是字符串,笔者被坑过)
    • 不仅能够遍历键名,还能够遍历手动增加的其余键,包含原型链上的
    • 某些状况下,会心任意秩序遍历
    • (for…in 次要为对象而设计的)

9. Generator 与 async await

generator 是 ES6 提供的一种异步编程解决方案。使异步写法更像同步。

Async await 是 ES2017 的规范,是 generator 的一个语法糖。

用法:

async function a() {
    await ...
    console.log(111)
    await ...
}

当执行 a 时,其不会阻塞涵数里面的代码(a 内的代码会安程序执行)

console.log('开始')
a()
console.log('a 前面')
// 开始 -> a 前面 -> 111        

10. Class

产生的起因:原 ES5 语法的没有成型的类的概念。而面向对象编程又离不开类的概念。

ES5 定义一个类:

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var p = new Point(1, 2)

ES6 的 class:

class Point {constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

其中:

  1. constructor 办法是类的默认办法,通过 new 命令生成对象时会调用该办法,如果申明类时没有定义 constructor,会默认定义一个空的。
  2. 生成实例时必须用 new , 不必会报错
  3. 不存在变里晋升(选定义类,再 new 实例)

类的静态方法:

所有在类中定义的办法都会被实例继承,如果不想被继承,能够在定义时加上 static。示意为静态方法。

class Foo {static match() {}}
Foo.match()
const f = new Foo()
f.match() // 报错

类的动态属性

很遗憾,ES6 没有给类设动态属性,然而能够用以下办法定义(有提案,写方同静态方法)

class Foo {}
 Foo.porp = 1
 // 应用
 Foo.porp // 1

类的实例属性

类的办法默认被实例继承,那么属性呢?也是继承的,写法如下:

class Foo {
    myProp = 111;
    ...
}

classr 的继承 extends

class Point {}
class PointSon extends Point {constructor(x, y, z) {super(x, y)
        this.z = z
    }
}

其中:

  1. super 等同于父类的 constructor。
  2. 子类必须在 constructor 中调用 super,也就是说用 extends 去继承一个类,就必须调用这个类(父类)的 constructor。是因为子类没有本人的 this 对象,而是继承父类的 this,而后对其进行加工
  3. 如果了类没有写 constructor,会默认生成一个,并蕴含了 super(…args)

11. Module

一种将程序拆分成一个个小模块的反对,或者说是能够将一个个小模块退出到程序中去。

在 ES6 的 module 之前,比拟风行的模块加载计划有:CommonJS 和 AMD,前者用于服务器(node),后者用于浏览器。

区别:

  1. CommondJS 和 AMD 是运行时加载的。
  2. module 是编译时加载的。
  3. CommondJS 输入的是值的复制,而 ES6 输入的是值的援用

ES6 模块默认应用严格模式

  • 变里必须申明后再应用
  • 函数的参数不能有同名属性
  • 不能应用 width
  • 禁止 this 指向全局对象

应用

命令有:exportimportexport default

文件 a.js

export a = 1
export b = 2

相当于

const a = 1;
const b = 2;
export  {a, b}

在文件 b.js 中引入

import {a, b} from './a.js'

引入是重命名

import {a as reA, b as reB} from './a.js' // reA reB 是重命名的变量

整体引入:

import * as all from './a.js'
all.a // 1
all.b // 2
// all 相当于{a, b}

export default 默认输入

export default 导出的模块在引入时能够自定义命名

export default function() {...}

仍然用 import 引入, 然而不必{},且能够自定义变量名

import name from './a.js'
name()

从一个模块导入,而后再导出

// 写法一:import {a, b} from './a.js'
export {a, b}
// 写法二:export {a, b} from './a.js'
// 改名导出
export {a as reA, b} from './a.js'
// 整体导出
export * from './a.js'

在浏览器中应用 module

将 script 标签的 type 设为 module 即可

<!--  办法一 -->
<script type="module" src="./a.js"></script>
<!-- 办法二 -->
<script type="module">
    import {a} from './a.js'
</script>

其中:

  • type=”module” 的 script 内写的代码是在以后作用域,不是在全局。
  • 模块内主动采纳严格模式
  • 顶层的 this 指向 undefined
  • 同一个模块如棵加载屡次,只执行一次

以上是 ES6 新增语法里在日常开发当中肯定会常常用到的货色。ES6 的订正对前端开发来说意义重大,其余的还有很多比方二进制数据、Proxy、Reflect、润饰器等,其内容稍深,能够到阮一峰老师博客看看,喜爱看书的能够买他的书《ES6 规范入门》超值。

正文完
 0