前端面试之ES6

ES6

var、let 和 const的区别

  • var变量

    • var 声明的变量会被提升作用域的顶部
    • var 声明的变量会被挂载到window
  • let和const

    • let 和 const 作用基本一致,但是const声明的变量不能再次赋值
    • 不会被挂载到window

提升(hoisting)

console.log(a)
var a = 1

虽然我们还没声明这个a,但是我们却可以打印这个a,并且输出undefined,这种情况就叫做提升,并且提升的是声明
不仅变量会提升,而且函数也会提升。

console.log(a)
function a(){

}
var a = 1

上面代码中,打印结果会是ƒ a(){ },及时也声明了变量a。
说明函数提升优于变量提升。

为什么需要提升?

提升存在的根本原因是为了解决函数互相调用的情况

function test1{
    test2()
}
function test2{
    test1()
}

Class

class MathHandle{
  constructor(x,y){
    this.x = x;
    this.y =y;    
  }
  add(){
    return this.x + this.y
  }
}
const m = new MathHandle(3,2);
console.log(m.add()) 

class是js构造函数的语法糖,本质就是函数

typeof MathHandle 输出function

MathHandle === MathHandle.prototype.constructor 输出true

Class继承

class Parent{
  constructor(value){
    this.val = value
  }
  getValue(){
    console.log(this.val)  
  }
}
class Child extends Parent{
  construct(value){
    super(value){
      this.val = value
    }
  }
}
let child = new Child();

这段代码可以看成Parent.call(this,value)

child instanceof Parent 输出true

子类构造函数中必须调用super

Class总结:

  • Class在语法上更加贴合面向对象的写法
  • Class实现继承更容易解读
  • 更易于写java等后端人员使用
  • 本质还是使用protoype

Promise

Promise是什么?

Promise是异步编程的解决方案,它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象

promise的构造函数是匿名函数,他有两个参数,一个是reject,一个是resolve,他们是两个函数

resolve的作用:
  • 把promise对象的状态置为成功
  • 异步操作结果value作为参数传给成功回调函数。
reject的作用:
  • 把promise对象的状态置为失败
  • 异步操作错误error作为参数返回失败回调函数。

不使用Promise请求图片

function loadimg(src,callback,fail)
{
  var img = document.createElement('img')
  img.onload = function(){
    callback(img)
  }
  img.onerror = function(){
    fail()
  }
  img.src = src;
}
var src = 'XXX'//图片链接
loadimg(src,function(img){
  console.log(img.width)
},function(){
  console.log('failed')
})

使用Promise请求图片

function loadimg(src){
  const promise = new Promise(function(reject,resolve){
    var img = document.createElement('img');
    img.onload = function(){
      resolve(img)
    }
    img.onerror = function(){
      reject
    }
    img.src = src
  })
  return promise;
}
var src = 'XXX'//图片链接
var result = loadimg(src)
result.then(function(img){
  console.log(img)
},function(){
  console.log('failed')
})
promise步骤:
  • 实例化promise对象
  • 传入函数
  • 并且return promise
  • 成功时执行resolve,失败时执行reject
  • then监听结果
catch捕获异常
result.then(function(img){
    console.log(img.width)
    return img;
}).then(function(img){
    console.log(img.height)
}).catch(function(ex){
    console.log(ex)
})​
Promise.all
Promise.all([result1,result2]).then(datas=>{
  console.log(datas[0])
  console.log(datas[1])
})
  • 接受一个数组作为参数,数组里的元素都是Promise对象的实例,如果不是,就会调用Promise.resolve方法,将参数转为Promise实例,再进一步处理。
  • 接收到的datas是一个数组,里面包含着多个promise返回的数组
  • 全部完成之后,才执行success
  • 当该数组里的某个Promise实例进入了rejected状态,Promise.all返回的实例会立即变成rejected状态,并将第一个rejected的实例返回值传递给Promise.all返回实例的回调函数。
Promise.race
Promise.all([result1,result2]).then(data=>{
  console.log(data)
})
  • Promise实例并不会等待所有Proimse都跑完,而是只要有一个Promise实例改变状态,它就跟着改变状态。并使用第一个改变状态实例的返回值作为返回值。
  • 谁跑得快谁先输出
Promise.resolve
Promise.resolve('foo');
//等价于
new Promise(resolve => resolve('foo'));
  • 该方法的作用是将现用对象转换成promise对象
Promise.reject
var p = Promise.reject('出错了');
//等价于
var p = new Promise((resolve,reject) => reject('出错了'));
//注意:Promise的参数为匿名函数,resolve不能写为null
p.then(null,function (s) {
  //then的两个参数也都为匿名构造函数
  console.log(s)
})
  • 会返回一个新的promise实例,状态为rejected

Promise标准

  • 状态:
    • Promise必须处于pending,resolved,rejected三个状态之一
    • 初始状态是pending
    • 状态变化不可逆
  • then:
    • Promise实例必须实现then这个方法
    • then()必须接收两个函数作为参数
      • resolve
      • reject
    • then()返回的必须是一个Promise实例

解构赋值

之前js的写法与ES6写法的比较

  • 以前js是这么写的
var obj =[a:100,b:200]
var a = obj.a
var b = obj.b
  • ES6
const obj =[a:100,b:200,c:300]
const [a,c] = obj;
console.log(a);//100
console.log(c);//300

块级作用域

以前是没有块级作用域的概念的,在for循环内部的变量能被外部访问

多行字符串/模板变量

const html = `

${name}

`

包裹在反引号内

箭头函数

之前js的写法与ES6写法的比较

  • 原JS
  var arr =[1,2,3]
  arr.map(function(item){
    item+1
  })
  • ES6
  const arr = [1,2,3]
  arr.map(item=>{
    item+1
  });
  arr.map((item,index)=>{
    console.log(index)
    return item+1
  });

Map

  • map的作用是生成一个新数组,遍历原数组,将每个元素拿出来做一些变换然后放入新的数组之中。
[1,2,3].map(v => v + 1) // [2,3,4]

map的回调函数接受三个参数,分别是当前索引元素索引原数组

['1','2','3'].map(parseInt)
输出1,NaN,NaN

  • parseInt('1', 0) -> 1
  • parseInt('2', 1) -> NaN
  • parseInt('3', 2) -> NaN
插入一下parseInt函数

parseInt(string, radix)

radix : 如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数,另外该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN

parseInt("10");         //返回 10
parseInt("19",10);      //返回 19 (10+9)
parseInt("11",2);       //返回 3 (2+1)
parseInt("17",8);       //返回 15 (8+7)
parseInt("1f",16);      //返回 31 (16+15)
parseInt("010");        //未定:返回 10 或 8

filter

  • filter的作用也是生成一个新数组,遍历数组的时候,将返回值为true的元素放入新数组。
let array = [1,2,4,6]
let newArray = array.filter(item=>item!=6)
console.log(newArray)

输出1,2,4

reduce

将数组里的全部元素相加得到一个值,可能会这么写

const arr=[1,2,3,4];
let total = 0;
for(let i = 0;i < arr.length;i++){
  total += arr[i]
}
console.log(total)

使用reduce就可以优化成一行代码

const arr = [1,2,3,4]
const sum = arr.reduce((acc,current)=>acc+current,0)
console.log(sum)

-对于reduce来说,它接受两个参数,一个是回调函数,一个是初始值。接下来我们来讲一下reduce的过程:

  • 首先初始值为 0,该值会在执行第一次回调函数时作为第一个参数传入
  • 回调函数接受四个参数,分别为累计值当前元素当前索引原数组,后三者想必大家都可以明白作用,这里着重分析第一个参数
  • 在一次执行回调函数时,当前值和初始值相加得出结果 1,该结果会在第二次执行回调函数时当做第一个参数传入
  • 所以在第二次执行回调函数时,相加的值就分别是 1 和 2,以此类推,循环结束后得到结果 6

模块化

为什么要使用模块化?

  • 解决命名冲突
  • 提供复用性
  • 提高代码维护性

在早期,使用了立即执行函数来解决命名冲突,污染全局作用域的问题

(function(globalVariable){
   globalVariable.test = function() {}
   // ... 声明各种变量、函数都不会污染全局作用域
})(globalVariable)

AMD

Asynchronous Module Definition,异步模块定义,所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。

// AMD
define(['./a', './b'], function(a, b) {
  // 加载模块完毕可以使用
  a.do()
  b.do()
})

CMD

// CMD
define(function(require, exports, module) {
  // 加载模块
  // 可以把 require 写在函数体的任意地方实现延迟加载
  var a = require('./a')
  a.doSomething()
})

对于依赖的模块,AMD 是提前执行,CMD 是延迟执行
AMD 推崇依赖前置,CMD 推崇依赖就近

CommonJS

// a.js
module.exports = {
    a: 1
}
// or 
exports.a = 1

// b.js
var module = require('./a.js')
module.a // -> log 1

ES Module

// 引入模块 API
import XXX from './a.js'
import { XXX } from './a.js'
// 导出模块 API
export function a() {}
export default function() {}

你可能感兴趣的:(前端面试之ES6)