面试问题整理

159 阅读6分钟

async/await

async function async1() {
    console.log("async1 start");
    await async2();
    console.log("async1 end");
}
async function async2() {
    console.log("async2");
}
console.log("script start");

setTimeout(function() {
    console.log("setTimeout");
}, 0);

async1();

new Promise(function(resolve) {
    console.log("promise1");
    resolve();
}).then(function() {
    console.log("promise2");
});

console.log("script end");

这道题在面试中出现的频率也是比较多的,第一次看到的时候感觉里面所有的东西都是那么的熟悉,但是又有一种不知从何处下手的感觉,瞬间就觉得这次面试完犊子了。

其实这道题里面有几个点

  • asyncawait
  • setTimeout
  • Promise

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。

await 用于等待一个Promise对象,它只能用于async函数中使用,否则会报错。

setTimeout 这个就涉及到javaScript的运行机制了:

我们都知道javaScript的一大特点就是单线程,也就是说,在同一时间内只能做一件事。这么设计的原因是因为JavaScript本身是一个浏览器的脚本语言,主要用途就是与用户互动以及操作dom,如果使用了多线程就会引发出很多复杂的同步问题。

但是单线程就决定了所有的任务都需要排队等待,也就是说在前一个任务没有结束的时候,后面的任务你知道在那眼巴巴的等着。

在JavaScript还只是一个简单的验证用户是否输入完整的时候这个机制还是没有问题的,但是到了现在JavaScript是越来越重要了,这种现象是我们无法忍受的。

于是,所有任务可以分为两种,一种是同步任务,一种是异步任务。同步任务指的是在主线程上所有排队的任务,只有前一个任务执行完毕了才会进入下一个任务;异步任务指的是不进入主线程而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

Promise是异步编程的一种解决方案,比传统的解决方案更合理更强大。我们可以把它看成一个容器,里面保存着一个在未来才会结束的事件,它有两个特点

  • 对象的状态不受外界的干扰,它代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败),只有异步操作的结果才可以改变它的状态
  • 一旦改变状态就会封存,不会再改变,任何时候都可以看到这个结果。及时是异步操作完成之后在加回调也是可以的。

    Promise 无法取消,创建就会执行

了解了这些之后下面来解这道题:

    async function async1() {
      console.log("async1 start");
      await async2();
      console.log("async1 end");
  }
  async function async2() {
      console.log("async2");
  }

首先是创建了两个带有async标记的函数,此时并未执行

console.log("script start");

接下来执行输出script start

    setTimeout(function() {
      console.log("setTimeout");
  }, 0);

执行setTimeout 在异步任务中加入一项待执行的任务,此时等所有的主线任务执行完毕。

    async1();

执行async1

  • 输出async1 start
  • 执行 async2 因为async2前面有await所有暂停执行下面的语句
new Promise(function(resolve) {
    console.log("promise1");
    resolve();
}).then(function() {
    console.log("promise2");
});

console.log("script end");

最后创建一个Promise,上面提到Promise在创建的时候回立刻执行,所以先输出promise1 然后是script end

此时所有的主线任务执行完毕回头来看还有哪些异步的任务,首先是async1中的,输出async1 end;Promise中的promise2;最后是setTimeout

class static

class a{
   static  xxx=function(a){
     console.log(a)
   }
  
}
  var f=new a();
  f.xxx('a')
  // 静态方法只能在Class上直接调用,不能使用class的示例对调用

array.map

console.log(["1","3","10"].map(parseInt));
// 考点为各进制直接的转换和map方法的使用,map会把每个项都当做回调函数的参数来
   执行,如果没有指定参数,默认为 当前项,当前索引,原数组

浏览器渲染页面的过程

  • 处理 HTML 标记并构建 DOM 树。
  • 处理 CSS 标记并构建 CSSOM 树。
  • 将 DOM 与 CSSOM 合并成一个渲染树。
  • 根据渲染树来布局,以计算每个节点的几何信息。
  • 将各个节点绘制到屏幕上。

$(this)和this的区别

前者是Jquery封装后的对象,具有jquery的属性方法,后者是JavaScript中的关键

用js取出数组中最大的数字

     function fn (array) { 
    // 将数组第一个元素的值赋给max 
    var max = array[0]; // 使用for 循环从数组第一个值开始做遍历 
    for (var i = 1; i < array.length; i++) { 
    // 如果元素当前值大于max,就把这个当前值赋值给max
    if (array[i] > max) { max = array[i]; } }
     // 返回最大的值 
         return max;
    } 
   
 Array.prototype.bubble_sort=function(){
  var i,j,temp;
   for(i=0;i<this.length;i++){
      for(j=0;j<this.length-1-i;j++){
          if(this[j]<this[j+1]){
             temp=this[j]
             this[j]=this[j+1]
             this[j+1]=temp
          }
      }
   }
 return this;
}

#手写Promise

         var myPromise=function(fn){
           this.status='pending';
              function resolve(){
                   this.status='resolved'

              }
              function reject(){
                  this.status='rejected'

              }
             fn(resolve,reject);

      }
   
   myPromise.prototype.then=function(success,error){

    if(this.status==='resolved')
       success()
     if(this.status==='rejected')
        error();

 }

document.ready和window.onload的区别

ready,表示文档结构(DOM结构)已经加载完成(不包含图片等非文字媒体文件), onload,指示页面包含图片等文件在内的所有元素都加载完成。

强制类型转换和隐士类型转换

通过String(),Number(),Boolean()函数强制转换

console.log(10+'20') //2010
console.log(10-'20')//-10 number
console.log(10-'one') //NaN not a number
console.log(10-'101a') //NaN
console.log(10*'20') //200 number
console.log('10'*'20') //200 number
console.log(20/'10') //2 number
console.log('20'/'10') //2 number
console.log('20'/'one') //NaN

继承的方法

function Parent(hello){
    this.hello = hello;
  }
  Parent.prototype.sayHello = function(){
    alert(this.hello);
  }
  
  function Child(hello,world){
    Parent.call(this,hello);//将父类的属性继承过来
    this.world = world;//新增一些属性
  }
  Child.prototype = new Parent();//将父类的方法继承过来
  Child.prototype.sayWorld = function(){//新增一些方法
    alert(this.world);
  }
  
  ======
  function Person(){
  }
  Person.prototype.hello = "hello";
  Person.prototype.sayHello = function(){
    alert(this.hello);
  }
  
  function Child(){
  }
  Child.prototype = new Person();//这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追加到Child,从而实现了继承
  Child.prototype.world = "world";
  Child.prototype.sayWorld = function(){
    alert(this.world);
  }
  

JS中 new 的作用

  • 创建一个临时对象
  • js会帮你指定原型
  • 执行一些操作
  • 返回这个临时对象

对闭包的理解

函数和函数内部能访问到的变量的环境,就是闭包

闭包通常会嵌套一个函数,可以隐藏变量