17 Generator 函数是什么,有什么作用?
-
如果说 JavaScript
是ECMAScript
标准的一种具体实现、Iterator
遍历器是Iterator
的具体实现,那么Generator
函数可以说是Iterator
接口的具体实现方式。 -
执行 Generator
函数会返回一个遍历器对象,每一次Generator
函数里面的yield
都相当一次遍历器对象的next()
方法,并且可以通过next(value)
方法传入自定义的 value,来改变Generator
函数的行为。 -
Generator
函数可以通过配合Thunk
函数更轻松更优雅的实现异步编程和控制流管理。
generator 原理
Generator
是ES6
中新增的语法,和Promise
一样,都可以用来异步编程
// 使用 * 表示这是一个 Generator 函数
// 内部可以通过 yield 暂停代码
// 通过调用 next 恢复执行
function* test() {
let a = 1 + 2;
yield 2;
yield 3;
}
let b = test();
console.log(b.next()); // > { value: 2, done: false }
console.log(b.next()); // > { value: 3, done: false }
console.log(b.next()); // > { value: undefined, done: true }
从以上代码可以发现,加上
*
的函数执行后拥有了next
函数,也就是说函数执行后返回了一个对象。每次调用next
函数可以继续执行被暂停的代码。以下是Generator
函数的简单实现
// cb 也就是编译过的 test 函数
function generator(cb) {
return (function() {
var object = {
next: 0,
stop: function() {}
};
return {
next: function() {
var ret = cb(object);
if (ret === undefined) return { value: undefined, done: true };
return {
value: ret,
done: false
};
}
};
})();
}
// 如果你使用 babel 编译后可以发现 test 函数变成了这样
function test() {
var a;
return generator(function(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
// 可以发现通过 yield 将代码分割成几块
// 每次执行 next 函数就执行一块代码
// 并且表明下次需要执行哪块代码
case 0:
a = 1 + 2;
_context.next = 4;
return 2;
case 4:
_context.next = 6;
return 3;
// 执行完毕
case 6:
case "end":
return _context.stop();
}
}
});
}
Generator 实现
Generator
是ES6
中新增的语法,和Promise
一样,都可以用来异步编程
// 使用 * 表示这是一个 Generator 函数
// 内部可以通过 yield 暂停代码
// 通过调用 next 恢复执行
function* test() {
let a = 1 + 2;
yield 2;
yield 3;
}
let b = test();
console.log(b.next()); // > { value: 2, done: false }
console.log(b.next()); // > { value: 3, done: false }
console.log(b.next()); // > { value: undefined, done: true }
从以上代码可以发现,加上
*
的函数执行后拥有了next
函数,也就是说函数执行后返回了一个对象。每次调用next
函数可以继续执行被暂停的代码。以下是Generator
函数的简单实现
// cb 也就是编译过的 test 函数
function generator(cb) {
return (function() {
var object = {
next: 0,
stop: function() {}
};
return {
next: function() {
var ret = cb(object);
if (ret === undefined) return { value: undefined, done: true };
return {
value: ret,
done: false
};
}
};
})();
}
// 如果你使用 babel 编译后可以发现 test 函数变成了这样
function test() {
var a;
return generator(function(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
// 可以发现通过 yield 将代码分割成几块
// 每次执行 next 函数就执行一块代码
// 并且表明下次需要执行哪块代码
case 0:
a = 1 + 2;
_context.next = 4;
return 2;
case 4:
_context.next = 6;
return 3;
// 执行完毕
case 6:
case "end":
return _context.stop();
}
}
});
}
18 async 函数是什么,有什么作用?
async
函数可以理解为内置自动执行器的Generator
函数语法糖,它配合ES6
的Promise
近乎完美的实现了异步编程解决方案
async、await 优缺点
async
和await
相比直接使用Promise
来说,优势在于处理 then 的调用链,能够更清晰准确的写出代码。缺点在于滥用await
可能会导致性能问题,因为await
会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性
下面来看一个使用 await
的代码。
var a = 0
var b = async () => {
a = a + await 10
console.log('2', a) // -> '2' 10
a = (await 10) + a
console.log('3', a) // -> '3' 20
}
b()
a++
console.log('1', a) // -> '1' 1
-
首先函数 b
先执行,在执行到await 10
之前变量a
还是0
,因为在await
内部实现了generators
,generators
会保留堆栈中东西,所以这时候a = 0
被保存了下来 -
因为 await
是异步操作,遇到await
就会立即返回一个pending
状态的Promise
对象,暂时返回执行代码的控制权,使得函数外的代码得以继续执行,所以会先执行console.log('1', a)
-
这时候同步代码执行完毕,开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 10
-
然后后面就是常规执行代码了
19 Class、extends 是什么,有什么作用?
ES6
的class
可以看作只是一个ES5
生成实例对象的构造函数的语法糖。它参考了java
语言,定义了一个类的概念,让对象原型写法更加清晰,对象实例化更像是一种面向对象编程。Class
类可以通过extends
实现继承。它和 ES5 构造函数的不同点
类的内部定义的所有方法,都是不可枚举的
///ES5
function ES5Fun (x, y) {
this.x = x;
this.y = y;
}
ES5Fun.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
}
var p = new ES5Fun(1, 3);
p.toString();
Object.keys(ES5Fun.prototype); //['toString']
//ES6
class ES6Fun {
constructor (x, y) {
this.x = x;
this.y = y;
}
toString () {
return '(' + this.x + ', ' + this.y + ')';
}
}
Object.keys(ES6Fun.prototype); //[]
-
ES6
的class
类必须用new
命令操作,而ES5
的构造函数不用new
也可以执行。 -
ES6
的class
类不存在变量提升,必须先定义class
之后才能实例化,不像ES5
中可以将构造函数写在实例化之后。 -
ES5
的继承,实质是先创造子类的实例对象this
,然后再将父类的方法添加到this
上面。ES6
的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this
上面(所以必须先调用super
方法),然后再用子类的构造函数修改this
。
20 module、export、import 是什么,有什么作用?
-
module
、export
、import
是ES6
用来统一前端模块化方案的设计思路和实现方案。export
、import
的出现统一了前端模块化的实现方案,整合规范了浏览器/服务端的模块化方法,用来取代传统的AMD/CMD
、requireJS
、seaJS
、commondJS
等等一系列前端模块不同的实现方案,使前端模块化更加统一规范,JS
也能更加能实现大型的应用程序开发。 -
import
引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)。 -
import
引入export
导出的接口值是动态绑定关系,即通过该接口,可以取到模块内部实时的值
21 日常前端代码开发中,有哪些值得用 ES6 去改进的编程优化或者规范?
-
常用箭头函数来取代 var self = this
;的做法。 -
常用 let
取代var
命令。 -
常用数组/对象的结构赋值来命名变量,结构更清晰,语义更明确,可读性更好。 -
在长字符串多变量组合场合,用模板字符串来取代字符串累加,能取得更好地效果和阅读体验。 -
用 Class
类取代传统的构造函数,来生成实例化对象。 -
在大型应用开发中,要保持 module
模块化开发思维,分清模块之间的关系,常用import
、export
方法。
22 ES6 的了解
新增模板字符串(为 JavaScript 提供了简单的字符串插值功能)、箭头函数(操作符左边为输入的参数,而右边则是进行的操作以及返回的值 Inputs=>outputs。)、for-of(用来遍历数据—例如数组中的值。)arguments 对象可被不定参数和默认参数完美代替。ES6 将 promise 对象纳入规范,提供了原生的 Promise 对象。增加了 let 和 const 命令,用来声明变量。增加了块级作用域。let 命令实际上就增加了块级作用域。ES6 规定,var 命令和 function 命令声明的全局变量,属于全局对象的属性;let 命令、const 命令、class 命令声明的全局变量,不属于全局对象的属性。。还有就是引入 module 模块的概念
23 说说你对 Promise 的理解
-
依照
Promise/A+
的定义,Promise 有四种状态:
-
pending
: 初始状态, 非fulfilled
或rejected.
-
fulfilled
: 成功的操作. -
rejected
: 失败的操作. -
settled
:Promise
已被fulfilled
或rejected
,且不是pending
-
另外,
fulfilled
与rejected
一起合称 settled -
Promise
对象用来进行延迟(deferred
) 和异步(asynchronous
) 计算 -
可以把
Promise
看成一个状态机。初始是pending
状态,可以通过函数resolve
和reject
,将状态转变为resolved
或者rejected
状态,状态一旦改变就不能再次变化。 -
then
函数会返回一个Promise
实例,并且该返回值是一个新的实例而不是之前的实例。因为Promise
规范规定除了pending
状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个then
调用就失去意义了
24 Promise 的构造函数
构造一个
Promise
,最基本的用法如下:
var promise = new Promise(function(resolve, reject) {
if (...) { // succeed
resolve(result);
} else { // fails
reject(Error(errMessage));
}
});
Promise
实例拥有 then 方法(具有 then 方法的对象,通常被称为 thenable)。它的使用方法如下:
promise.then(onFulfilled, onRejected)
接收两个函数作为参数,一个在
fulfilled
的时候被调用,一个在rejected
的时候被调用,接收参数就是 future,onFulfilled
对应resolve
,onRejected
对应reject
什么是 Promise ?
-
Promise 就是一个对象,用来表示并传递异步操作的最终结果 -
Promise 最主要的交互方式:将回调函数传入 then 方法来获得最终结果或出错原因 -
Promise 代码书写上的表现:以“链式调用”代替回调函数层层嵌套(回调地狱)
原文始发于微信公众号(消失的程序员):ES6 面试题精选3
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/250720.html