ES6 面试常考题库【2】

文章详细介绍了JavaScript中的Symbol数据类型,包括其唯一性和用于对象属性的独特性。接着讨论了迭代器的概念和工作原理,通过示例展示了如何在对象和数组中使用。然后,深入讲解了Promise在异步编程中的角色,以及如何定义和使用生成器函数。最后,讨论了Promise的使用,包括解决回调地狱问题及基本的Promise方法如then和catch。
摘要由CSDN通过智能技术生成

第二篇


一些常见的面试题内容,希望也能助你一臂之力🌸🌸🌸🌸🌸

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)
	});
	//执行结果: Hello4)不带有任何参数
	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)
});
// 执行结果:出错了

休息一下,下一篇下一篇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值