第二篇
一些常见的面试题内容,希望也能助你一臂之力🌸🌸🌸🌸🌸
Q1、什么是Symbol?
ES6新增的一种数据类型。
特点:(1)类似字符串
(2)值唯一,解决命名冲突
(3)不能与其他数据进行运算
Q2、如何创建一个symbol类型的对象以及添加属性和方法?
//举个例子
// 使用Symbol创建对象
let s = Symbol();
// let s = Symbol(); //命名不能重复
let s1 = Symbol('小王');
let s2 = Symbol('小王');
console.log(s1 == s2); //false
// 使用 Symbol() 标识的变量,表示该变量独一无二
// Symbol.for创建
let s4 = Symbol.for('小张');
let s5 = Symbol.for('小张');
console.log(s4 == s5); //true
// Symbol.for() 接受一个字符串作为参数,被登记在全局环境中供搜索
// 创建一个Symbol.for(),先搜索有没有以该参数作为名称的Symbol值,
// 如果有,就返回这个Symbol值,
// 否则就新建并返回一个该字符串为名称的Symbol值
// 添加属性和方法
// 向对象添加属性和方法 up down
// 声明一个对象
let game = {
name:'五子棋',
play:function(){}
}
// 声明一个对象
let methods = {
up:Symbol(),
down:Symbol()
}
game[methods.up] = function(){
console.log("向上")
},
game[methods.down] = function(){
console.log("向下")
}
console.log(game);
// 结果:{name: '五子棋', play: ƒ, Symbol(): ƒ, Symbol(): ƒ}
let youxi = {
name:'狼人杀',
[Symbol('say')]:function(){
console.log('say')
}
}
console.log(youxi);
// 结果:{name: '狼人杀', Symbol(say): ƒ}
Q3、什么是迭代器?
为各种不同的数据解构提供统一的访问机制,任何数据结构只需要部署Iterator接口,可以完成遍历操作
Iterator接口(对象里面的属性)
Q 4、迭代器的工作原理
(1)创建一个指针对象,指向当前数据结构的起始位置
(2)第一次调用next,指针指向数据的第一个成员
(3)每次调用next方法返回一个包含value和done属性的对象
// 举个例子
// 声明一个数组
const arr = ['a','b','c','d'];
// 使用for ..in遍历数组
for(let v in arr){
console.log(v);
// 结果:0 1 2 3 ,遍历出来的索引
}
for(let v of arr){
console.log(v);
// 结果:a,b,c,d , 遍历出来的是值
}
// 声明一个数组
const movie = ['西游记','红楼','水浒','三国'];
// 创建一个迭代对象
let iterator = movie[Symbol.iterator]();
// 调用对象的next方法
console.log(iterator.next()); // {value: '西游记', done: false}
console.log(iterator.next()); // {value: '红楼', done: false}
console.log(iterator.next()); // {value: '水浒', done: false}
console.log(iterator.next()); // {value: '三国', done: false} 最后一个
console.log(iterator.next()); // {value: undefined, done: true} done为true表示结束
// 迭代器应用
// 自定义遍历数据
// 声明一个对象
const banji = {
name:'十三',
stus:[
'xiaowang',
'xiaozhang',
'xiaotian',
'xiaowu'
],
[Symbol.iterator](){
// 索引变量
let index = 0;
// 保存this
let _this = this; // 使用_this保存当前的this
return {
next:function(){
if(index < _this.stus.length){
const result = {value:_this.stus[index],done:false};
// 下标自增
index++;
// 返回结果
return result;
}else{
return {value:undefined,done:true}
}
}
};
}
}
// 遍历这个对象 //返回对象数组中的一个成员
for(let v of banji){
console.log(v);
// 结果 xiaowang,xiaozhang,xiaotian,xiaowu
}
Q5、如何定义生成器以及获取对象?
生成器函数,是异步编程【对以前纯回调函数优化】
// 定义
function * gen(){
// yield代码分块,没调用一次next往下执行一次
console.log("生成器gen");
yield'-------';
console.log("第二块代码");
yield'-------';
console.log("第三块代码");
}
// 调用,借助iterator的next方法
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 结果
/*
生成器gen
{value: '-------', done: false}
第二块代码
{value: '-------', done: false}
第三块代码
{value: undefined, done: true}
*/
// 遍历
for(let v of gen()){
console.log(v);
}
// 结果
/*
生成器gen
-------
第二块代码
-------
第三块代码
*/
// 生成器函数参数
function * gen(arg){
console.log(arg)
let one = yield 111;
console.log(one)
let two = yield 222;
console.log(two)
let three = yield 333;
console.log(three)
}
// 获取对象
let iterator = gen('第一个实参');
// 调用next方法,next可以传入实参
console.log(iterator.next());//根据他的原理,默认指向第一个
console.log(iterator.next('第二个实参'));
console.log(iterator.next('第三个实参'));
console.log(iterator.next('第四个实参'));
// 结果
/*
第一个实参
{value: 111, done: false}
第二个实参
{value: 222, done: false}
第三个实参
{value: 333, done: false}
第四个实参
{value: undefined, done: true}
*/
Q6、什么是Promise,它解决了什么问题?
(1)Promise 是异步编程的一种解决方案,相对于传统的 回调函数和事件 更合理和更强大。
(2)它也是一个对象,从它可以获取异步操作的消息。
(3)提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象特点:
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending、fulfilled和rejected。
(2))一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。
解决问题:
(1)有了Promise对象,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数(回调地狱)。
(2)此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
存在问题:
(1)无法取消Promise,一旦新建它就会立即执行,无法中途取消。
(2)如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
(3)当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
Q7、promise基本使用
//举个例子
const p = new Promise(function(resolve,reject){
setTimeout(function(){
// promise封装的函数对象resolve reject
// case1:
// let data = '数据库中数据';
// resolve(data);
// case2:
let err = '数据库读取失败';
reject(err);
},1000)
})
// 调用promise对象的then方法
p.then(function(value){
// 成功 返回value
console.log(value); // 结果: 读取数据库成功
},function(reason){
// 失败 放回reason
console.log(reason); // 失败:数据库读取失败
})
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),并将结果传递出去。
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),并将结果传递出去。
then方法分别指定resolved状态和rejected状态的回调函数。
// Promise新建后就会立即执行
let promise = new Promise(function(resolve,reject){
console.log('Promise');
resolve();
})
console.log(2);
promise.then(function(){
console.log('resolved')
})
console.log('3');
执行结果:Promise 2 3 resolved
Promise新建后立即执行->执行同任务->执行then方法指定的回调。
Q8、如何使用Promise对象实现的 Ajax 操作的例子?
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
// 执行成功的结果
resolve(this.response);
} else {
// 执行失败的结果
reject(new Error(this.statusText));
}
};
// http实例
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
// getJSON是对 XMLHttpRequest 对象的封装,
// 用于发出一个针对 JSON 数据的 HTTP 请求,
// 并且返回一个Promise对象
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});
Q9、Promise中异步执行的特点?
一、一个异步操作的结果是返回另一个异步操作
const p1 = new Promise(function (resolve, reject) {
// ...
});
const p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})
p1和p2都是 Promise 的实例,但是p2的resolve方法将p1作为参数。
这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。
(1)如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;
(2)如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。
二、调用resolve或reject并不会终结 Promise 的参数函数的执行
new Promise((resolve, reject) => {
resolve(1);
console.log(2); // 同步任务
}).then(r => {
console.log(r);
});
// 执行结果:2 1
// 执行顺序 本轮循环的同步任务-> 立即 resolved 的 Promise 是事件循环
三、尽量避免在调用resolve或reject以后执行代码
new Promise((resolve, reject) => {
return resolve(1);
// 后面的语句不会执行
console.log(2);
})
Q10、Promise有哪些方法?【by:es6 阮一峰】
一、Promise.prototype.then()
Promise 实例具有then方法,是定义在原型对象Promise.prototype上的。
作用:为 Promise 实例添加状态改变时的回调函数。
参数:第一个参数是resolved状态的回调函数,
第二个参数是rejected状态的回调函数,它们都是可选的
// 创建一个promise对象
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
// resolve('用户数据');
reject('出错了');
},1000)
})
// 调用then方法,then方法返回结果是Promise对象,
// 对象状态由回调函数的执行结果决定
const result = p.then(value=>{
// 返回类型
// promise对象
return new Promise((resolve,reject)=>{
console.log('第一个then,执行结果='+ value);
// resolve('ok');
reject('error')
})
//3、抛出错误
// throw new Error("出错了!")
},
).then(value=>{
console.log(111); //
})
// 第一个then方法指定的回调函数,返回的是另一个Promise对象。
// 这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。
// 如果变为resolved,就调用第一个回调函数,然后执行第二个then
// 如果状态变为rejected,不执行then
二、Promise.prototype.catch()
Promise.prototype.catch()方法是
.then(null, rejection)
或.then(undefined, rejection)的别名,
用于指定发生错误时的回调函数。
// 举个例子
// 如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
//promise抛出一个错误,就被catch()方法指定的回调函数捕获
promise.catch(function(error) {
console.log(error);
});
// 执行结果 Error test
// 写法一
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 写法二
const promise = new Promise(function(resolve, reject) {
// reject()方法的作用,等同于抛出错误。
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
// 写法特点
不要在then()方法里面定义 Reject 状态的回调函数(即then的第二个参数),推荐使用catch方法。
// 举个例子
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
原因是:
(1)第二种写法可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch)
(2)Promise 对象后面跟catch()方法,这样可以处理 Promise 内部发生的错误。
(3)catch()方法返回的还是一个 Promise 对象,因此后面还可以接着调用then()方法。
三、 Promise.prototype.finally()
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
// 举个例子
// 服务器使用 Promise 处理请求,然后使用finally方法关掉服务器。
server.listen(port)
.then(function () {
// ...
})
.finally(server.stop);
// Promise 返回值不管是fulfilled还是rejected,都会执行回调函数callback。
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
四、Promise.all()
Promise.all()方法只适合所有异步操作都成功的情况,如果有一个操作失败,就无法满足要求。
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
// Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
const p = Promise.all([p1, p2, p3]); // p1、p2、p3都是 Promise 实例
p的结果状态:
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,
此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,
此时第一个被reject的实例的返回值,会传递给p的回调函数。
// 举个例子
//promises是包含 6 个 Promise 实例的数组,只有这 6 个实例的状态都变成fulfilled,
// 或者其中有一个变为rejected,才会调用Promise.all方法后面的回调函数。
// 生成一个Promise对象的数组
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
return getJSON('/post/' + id + ".json");
});
Promise.all(promises).then(function (posts) {
// ...
}).catch(function(reason){
// ...
});
五、Promise.race()
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
// 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。
// 那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
六、Promise.allSettled()
(1)Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。
(2)只有等到参数数组的所有 Promise 对象都发生状态变更(不管是fulfilled还是rejected),返回的 Promise 对象才会发生状态变更。
七、Promise.any()
(1)只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;
(2)如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法的相/不同
相同点:Promise.any()跟Promise.race()方法都依赖某个异步操作的结果
不同点:Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。
// 举个例子
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);
Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
console.log(result); // 42
});
Promise.any([rejected, alsoRejected]).catch(function (results) {
console.log(results instanceof AggregateError); // true
// AggregateError 实例对象的errors属性是一个数组,包含了所有成员的错误。
console.log(results.errors); // [-1, Infinity]
});
八、Promise.resolve()
可以将现有对象转为 Promise 对象,Promise.resolve()方法就起到这个作用。
const jsPromise = Promise.resolve($.ajax('/whatever.json'));
// 上面代码将 jQuery 生成的deferred对象,转为一个新的 Promise 对象。
// resolve 参数
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象
thenable对象指的是具有then方法的对象
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
//Promise.resolve()方法会将这个对象转为 Promise 对象,
//然后就立即执行thenable对象的then()方法。
(3)参数不是具有then()方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then()方法的对象,
则Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello');
p.then(function (s) {
console.log(s)
});
//执行结果: Hello
(4)不带有任何参数
Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
直接调用Promise.resolve()方法可以得到一个 Promise 对象。
九、Promise.reject()
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
//生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 执行结果:出错了
休息一下,下一篇下一篇