本篇文章是根据以下内容进行的总结

1、https://segmentfault.com/a/1190000011344301

2、http://www.bslxx.com/a/mianshiti/tiku/2017/1019/953.html

3、http://www.bslxx.com/a/mianshiti/tiku/javascript/2017/1213/1505.html

前言

自从ES6发布以来,就受到了广大开发者的欢迎。它的新特性解决了很多实际开发中的痛点,并且使得JavaScript逐步成为一门能够开发大型企业应用的编程语言,基于这种技术环境下,很多公司都将ES6视为开发的其中一个标准,因此在招聘人才的时候,也会对其进行ES6知识的考察。下面就来看看哪些ES6知识是我们需要重点掌握的。

箭头函数需要注意的地方

*当要求动态上下文的时候,就不能够使用箭头函数,也就是this的固定化。

1、在使用=>定义函数的时候,this的指向是定义时所在的对象,而不是使用时所在的对象;
2、不能够用作构造函数,这就是说,不能够使用new命令,否则就会抛出一个错误;
3、不能够使用arguments对象;
4、不能使用yield命令;

下面来看一道面试题,重点说明下第一个知识点:

class Animal {
constructor() {
this.type = "animal";
}
say(val) {
setTimeout(function () {
console.log(this); //window
console.log(this.type + " says " + val);
}, 1000)
}
}
var animal = new Animal();
animal.say("hi"); //undefined says hi

【拓展】

《JavaScript高级程序设计》第二版中,写到:“超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined”。也就是说在非严格模式下,setTimeout中所执行函数中的this,永远指向window!!

我们再来看看箭头函数(=>)的情况:

class Animal {
constructor() {
this.type = "animal";
}
say(val) {
setTimeout(() => {
console.log(this); //Animal
console.log(this.type + ' says ' + val);
}, 1000)
}
}
var animal = new Animal();
animal.say("hi"); //animal says hi

【特点】

  • 不需要function关键字来创建函数
  • 省略return关键字
  • 继承当前上下文的 this 关键字

let和const

*let是更完美的var,不是全局变量,具有块级函数作用域,大多数情况不会发生变量提升。const定义常量值,不能够重新赋值,如果值是一个对象,可以改变对象里边的属性值。

1、let声明的变量具有块级作用域
2、let声明的变量不能通过window.变量名进行访问
3、形如for(let x..)的循环是每次迭代都为x创建新的绑定

下面是var带来的不合理场景

var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function () {
console.log(i);
}
}
arr[5]() //10,a[5]输出f(){console.log(i);},后面加个括号代表执行f()

在上述代码中,变量i是var声明的,在全局范围类都有效,所以用来计数的循环变量泄露为全局变量。所以每一次循环,新的i值都会覆盖旧值,导致最后输出都是10。

而如果对循环使用let语句的情况,那么每次迭代都是为x创建新的绑定代码如下:

var arr = [];
for (let i = 0; i < 10; i++) {
arr[i] = function () {
console.log(i);
}
}
arr[5]() //5,a[5]输出f(){console.log(i);},后面加个括号代表执行f()

【拓展】

当然,除了这种方式让数组找中的各个元素分别是不同的函数,我们还可以采用ES5中的闭包和立即函数两种方法。

1、采用闭包

function showNum(i) {
return function () {
console.log(i)
}
}
var a = []
for (var i = 0; i < 5; i++) {
a[i] = showNum(i)(); //循环输出1,2,3,4
}

2、采用立即执行函数

var a = []
for (var i = 0; i < 5; i++) {
a[i] = (function (i) {
return function () {
console.log(i)
}
})(i)
}
a[2](); //

【面试】

把以下代码使用两种方法,依次输出0-9

var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i)
})
}
funcs.forEach(function (func) {
func(); //输出十个10
})

方法一:使用立即执行函数

var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push((function (value) {
return function () {
console.log(value)
}
}(i)))
}
funcs.forEach(function (func) {
func(); //依次输出0-9
})

方法二:使用闭包

function show(i) {
return function () {
console.log(i)
}
}
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(show(i))
}
funcs.forEach(function (func) {
func(); //0 1 2 3 4 5 6 7 8 9
})

方法三:使用let

var funcs = []
for (let i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i)
})
}
funcs.forEach(function (func) {
func(); //依次输出0-9
})

其他知识点:forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。戳这里查看参考文章

Set数据结构

*es6方法,Set本身是一个构造函数,它类似于数组,但是成员值都是唯一的。

const set = new Set([1,2,3,4,4])
console.log([...set] )// [1,2,3,4]
console.log(Array.from(new Set([2,3,3,5,6]))); //[2,3,5,6]

Class的讲解

*class语法相对原型、构造函数、继承更接近传统语法,它的写法能够让对象原型的写法更加清晰、面向对象编程的语法更加通俗
这是class的具体用法。

class Animal {
constructor() {
this.type = 'animal'
}
says(say) {
console.log(this.type + 'says' + say)
}
}
let animal = new Animal()
animal.says('hello') // animal says hello class Cat extends Animal {
constructor() {
super()
this.type = 'cat'
}
}
let cat = new Cat()
cat.says('hello') // cat says hell

可以看出在使用extend的时候结构输出是cat says hello 而不是animal says hello。说明contructor内部定义的方法和属性是实例对象自己的,不能通过extends 进行继承。在class cat中出现了super(),这是什么呢?因为在ES6中,子类的构造函数必须含有super函数,super表示的是调用父类的构造函数,虽然是父类的构造函数,但是this指向的却是cat。

更详细的参考文章

模板字符串

*就是这种形式${varible},在以往的时候我们在连接字符串和变量的时候需要使用这种方式'string' + varible + 'string'但是有了模版语言后我们可以使用string${varible}string这种进行连接。基本用途有如下:

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

//es5
var name = 'lux';
console.log('hello' + name);
//es6
const name = 'lux';
console.log(`hello ${name}`); //hello lux

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

//ES5
var template = "hello \
world";
console.log(template); //hello world //ES6
const template = `hello
world`;
console.log(template); //hello 空行 world

【拓展】

字符串的其他方法

// 1.includes:判断是否包含然后直接返回布尔值
let str = 'hahay'
console.log(str.includes('y')) // true // 2.repeat: 获取字符串重复n次
let s = 'he'
console.log(s.repeat(3)) // 'hehehe'

重点“人物”:Promise!

概念:Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合合理、强大。所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promies是一个对象,从它可以获取异步操作的消息。Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。处理过程流程图:

【面试套路1】

手写一个promise

var promise = new Promise((resolve, reject) => {
if (操作成功) {
resolve(value)
} else {
reject(error)
}
})
promise.then(function (value) {
// success
}, function (value) {
// failure
})

【面试套路2】

怎么解决回调函数里面回调另一个函数,另一个函数的参数需要依赖这个回调函数。需要被解决的代码如下:

$http.get(url).success(function (res) {
if (success != undefined) {
success(res);
}
}).error(function (res) {
if (error != undefined) {
error(res);
}
}); function success(data) {
if( data.id != 0) {
var url = "getdata/data?id=" + data.id + "";
$http.get(url).success(function (res) {
showData(res);
}).error(function (res) {
if (error != undefined) {
error(res);
}
});
}
}

【面试套路3】

以下代码依次输出的内容是?

setTimeout(function () {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for (var i = 0; i < 10000; i++) {
i == 9999 && resolve();
}
console.log(3);
}).then(function () {
console.log(4);
});
console.log(5);

上述代码解析:

首先先碰到一个 setTimeout,于是会先设置一个定时,在定时结束后将传递这个函数放到任务队列里面,因此开始肯定不会输出 1 。 

然后是一个 Promise,里面的函数是直接执行的,因此应该直接输出 2 3 。 

然后,Promise 的 then 应当会放到当前 tick 的最后,但是还是在当前 tick 中。 

因此,应当先输出 5,然后再输出 4 , 最后在到下一个 tick,就是 1 。

【面试套路4】

jQuery的ajax返回的是promise对象吗?

jquery的ajax返回的是deferred对象,通过promise的resolve()方法将其转换为promise对象。

var jsPromise = Promise.resolve($.ajax('/whatever.json'));

【面试套路5】

promise只有2个状态,成功和失败,怎么让一个函数无论成功还是失败都能被调用?

使用promise.all()

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。

Promise.all方法接受一个数组作为参数,数组里的元素都是Promise对象的实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。)

示例:
var p =Promise.all([p1,p2,p3]);
p的状态由p1、p2、p3决定,分为两种情况。
当该数组里的所有Promise实例都进入Fulfilled状态:Promise.all**返回的实例才会变成Fulfilled状态。并将Promise实例数组的所有返回值组成一个数组,传递给Promise.all返回实例的回调函数**。 当该数组里的某个Promise实例都进入Rejected状态:Promise.all返回的实例会立即变成Rejected状态。并将第一个rejected的实例返回值传递给Promise.all返回实例的回调函数。

【面试套路6】

一、分析下列程序代码,得出运行结果,解释其原因

const promise = new Promise((resolve, reject) => {
console.log(1)
resolve()
console.log(2)
})
promise.then(() => {
console.log(3)
})
console.log(4)

运行结果及原因

运行结果:
1 2 4 3 原因:
Promise 构造函数是同步执行的,promise.then 中的函数是异步执行的。

二、分析下列程序代码,得出运行结果,解释其原因

const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
const promise2 = promise1.then(() => {
throw new Error('error!!!')
}) console.log('promise1', promise1)
console.log('promise2', promise2) setTimeout(() => {
console.log('promise1', promise1)
console.log('promise2', promise2)
}, 2000)

运行结果及原因

运行结果:
promise1 Promise { <pending> }
promise2 Promise { <pending> }
(node:50928) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: error!!!
(node:50928) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
promise1 Promise { 'success' }
promise2 Promise {
<rejected> Error: error!!!
at promise.then (...)
at <anonymous> } 原因:
promise 有 3 种状态:pending(进行中)、fulfilled(已完成,又称为Resolved) 或 rejected(已失败)。状态改变只能是 pending->fulfilled 或者 pending->rejected,状态一旦改变则不能再变。上面 promise2 并不是 promise1,而是返回的一个新的 Promise 实例。

三、分析下列程序代码,得出运行结果,解释其原因

const promise = new Promise((resolve, reject) => {
resolve('success1')
reject('error')
resolve('success2')
}) promise
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})

运行结果及原因

运行结果:
then:success1 原因:
构造函数中的 resolve 或 reject 只有第一次执行有效,多次调用没有任何作用,呼应代码二结论:promise 状态一旦改变则不能再变。

四、分析下列程序代码,得出运行结果,解释其原因

Promise.resolve(1)
.then((res) => {
console.log(res)
return 2
})
.catch((err) => {
return 3
})
.then((res) => {
console.log(res)
})

运行结果及原因

运行结果:
1 2 原因:
promise 可以链式调用。提起链式调用我们通常会想到通过 return this 实现,不过 Promise 并不是这样实现的。promise 每次调用 .then 或者 .catch 都会返回一个新的 promise,从而实现了链式调用。

五、分析下列程序代码,得出运行结果,解释其原因

const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('once')
resolve('success')
}, 1000)
}) const start = Date.now()
promise.then((res) => {
console.log(res, Date.now() - start)
})
promise.then((res) => {
console.log(res, Date.now() - start)
})

运行结果及原因

运行结果:
once
success 1001
success 1001 原因:
promise 的 .then 或者 .catch 可以被调用多次,但这里 Promise 构造函数只执行一次。或者说 promise 内部状态一经改变,并且有了一个值,那么后续每次调用 .then 或者 .catch 都会直接拿到该值。

六、分析下列程序代码,得出运行结果,解释其原因

Promise.resolve()
.then(() => {
return new Error('error!!!')
})
.then((res) => {
console.log('then: ', res)
})
.catch((err) => {
console.log('catch: ', err)
})

运行结果及原因

运行结果
then: Error: error!!!
at Promise.resolve.then (...)
at ... 原因
.then 或者 .catch 中 return 一个 error 对象并不会抛出错误,所以不会被后续的 .catch 捕获,需要改成其中一种:
return Promise.reject(new Error('error!!!'))
throw new Error('error!!!') 因为返回任意一个非 promise 的值都会被包裹成 promise 对象,即 return new Error('error!!!') 等价于 return Promise.resolve(new Error('error!!!'))。

七、分析下列程序代码,得出运行结果,解释其原因

const promise = Promise.resolve()
.then(() => {
return promise
})
promise.catch(console.error)

运行结果及原因

运行结果
TypeError: Chaining cycle detected for promise #<Promise>
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
at Function.Module.runMain (module.js:667:11)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:607:3 原因
.then 或 .catch 返回的值不能是 promise 本身,否则会造成死循环。

八、分析下列程序代码,得出运行结果,解释其原因

Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log)

运行结果及原因

运行结果
1 原因
.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。

九、分析下列程序代码,得出运行结果,解释其原因

Promise.resolve()
.then(function success (res) {
throw new Error('error')
}, function fail1 (e) {
console.error('fail1: ', e)
})
.catch(function fail2 (e) {
console.error('fail2: ', e)
})

运行结果及原因

运行结果
fail2: Error: error
at success (...)
at ... 原因
.then 可以接收两个参数,第一个是处理成功的函数,第二个是处理错误的函数。.catch 是 .then 第二个参数的简便写法,但是它们用法上有一点需要注意:.then 的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,而后续的 .catch 可以捕获之前的错误。

十、分析下列程序代码,得出运行结果,解释其原因

process.nextTick(() => {
console.log('nextTick')
})
Promise.resolve()
.then(() => {
console.log('then')
})
setImmediate(() => {
console.log('setImmediate')
})
console.log('end')

运行结果及原因

运行结果
end
nextTick
then
setImmediate 原因
process.nextTick 和 promise.then 都属于 microtask,而 setImmediate 属于 macrotask,在事件循环的 check 阶段执行。事件循环的每个阶段(macrotask)之间都会执行 microtask,事件循环的开始会先执行一次 microtask。

ES6高频面试题目整理的更多相关文章

  1. C++常见的面试题目整理

    本文列出C++面试中经常遇到的一些问题,都是一些常见的面试考点,如果后续遇到其他常见面试问题还会再次更新.希望对近期参加面试的同学有一些帮助.先后顺序与问题的重要性无关,查看的时候,最好是全面了解一下 ...

  2. 【Android进阶】Android面试题目整理与讲解(一)

    这一篇文章专门整理一下研究过的Android面试题,内容会随着学习不断的增加,如果答案有错误,希望大家可以指正 1.简述Activity的生命周期 当Activity开始启动的时候,首先调用onCre ...

  3. 【转载】最全的面试题目整理(HTML+CSS部分)

    转载自 知乎 @西点王子 https://www.zhihu.com/people/F211/answers 1. 常用那几种浏览器测试?有哪些内核(Layout Engine)? (Q1) 浏览器: ...

  4. Android面试题目整理与解说(一)

    这一篇文章专门整理一下研究过的Android面试题,内容会随着学习不断的添加,假设答案有错误,希望大家能够指正 1.简述Activity的生命周期 当Activity開始启动的时候,首先调用onCre ...

  5. 【Java基础】Java面试题目整理与解说(二)

    1.Collection 和 Collections 的差别. Collection 是集合类的上级接口,继承于他的接口主要有 Set 和 List. Collections 是针对集合类的一个帮助类 ...

  6. 【Android进阶】Android面试题目整理与讲解(二)

    1. ArrayList,Vector, LinkedList 的存储性能和特性 ArrayList 和 Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们 ...

  7. Android面试题目整理与解说(二)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/bz419927089/article/details/31386787 1.Dalvik和标准Jav ...

  8. C#面试题目整理(一)

    1.您在什么情况下会用到虚方法?它与接口有什么不同?当子类需要重新定义父类的一个方法时,父类的方法需要定义为虚方法:在定义接口的时候不能又方法体,但是虚方法可以有方法体,实现时,子类可以不实现父类的虚 ...

  9. 总结CSS面试题目的考察点及常见布局问题整理

    整理网上流传的若干份面试题目,突发奇想,总结关于CSS面试题目的考察点,发现问题大多围绕几个属性和几种题目,水平有限,仅供参考. 写这个博文内心有种莫名奇妙的自我谴责感,实在不应该把面试层叠样式“应试 ...

随机推荐

  1. centos 7 keepalived故障邮件通知实战(附Python邮件发送脚本)

    centos 7 keepalived故障邮件通知实战(附Python邮件发送脚本) #####################     sendmail.py  begin     ######## ...

  2. Storm原理及安装

    http://my.oschina.net/leejun2005/blog/147607 http://www.storm-geek.com/forum.php http://www.zhangjih ...

  3. Android 开发工具类 06_NetUtils

    跟网络相关的工具类: 1.判断网络是否连接: 2.判断是否是 wifi 连接: 3.打开网络设置界面: import android.app.Activity; import android.cont ...

  4. Javac语法糖之EnumSwitch

    在Switch中可以使用的类型有枚举.字符串类型与整形int类型,下面来具体看这几个类型. 1.switch为枚举类型 枚举类: enum Fruit { APPLE,ORINGE } 调用javac ...

  5. no awt in java.libary.path

    缺少依赖包. linux下进入jdk安装路径/jre/lib/i386 使用ldd查看依赖包情况: ldd libawt.so 如果发现有not found的,就安装上,或者从jdk下查找,使用软连接 ...

  6. [转]SQL Server 2008- Get table constraints

    本文转自:https://stackoverflow.com/questions/14229277/sql-server-2008-get-table-constraints You should u ...

  7. elasticsearch 分布式集群搭建

    elasticsearch环境搭建及单节点搭建可参考我的上一篇:http://www.cnblogs.com/xuwenjin/p/8745624.html 本文以Elaticsearch 6.2.2 ...

  8. C# 代码占用的空间

    是不是代码会占用空间,如果一个程序初始化需要 100M 的代码,那么在他初始化之后,这些代码就没有作用了,他会不会占空间?本文经过测试发现,代码也是会占空间. 我写了2k个垃圾类代码,然后把他放在一个 ...

  9. MSSQL存储过程实现拼接sql的注意点

    这里我昨天碰到的问题就是执行一段根据变量tableName对不同的表进行字段状态的更改.由于服务器原因,我不能直接在数据访问层写SQL,所以只好抽离出来放到存储过程里面. 这里就出现了一个问题,我花费 ...

  10. iOS交互h5——user-agent

    User-Agent(用户代理)字符串是Web浏览器用于声明自身型号版本并随HTTP请求发送给Web服务器的字符串,在Web服务器上可以获取到该字符串. 在公司产品中,在userAgent中增加了XX ...