基础面试题js

2021-10-20  本文已影响0人  大萝蓓

1、js的this是怎么工作的?(这个大概就是问this是什么)
答:1、this总是指向函数的直接调用者。2、如果有new关键字,this指向new出来的那个对象。3、在MOD实践中,this指向目标元素。4、箭头函数的this指向它所在的函数作用域,并且不能改变,始终指向的是window。
2、原型继承的原理?
答:
3、什么是闭包,怎么用?
答:在js中函数可以访问函数外部的变量的,但是在外部拿不到内部的变量,A一个函数,B是A里面的子函数,在B里面把A的变量return出去,再把B函数给return出去,如果我要用A里面的变量就可以直接调用B函数了,这个就是闭包。
优点:可访问函数内部的变量,防止变量污染作用域(隐藏变量),从而实现封装。
缺点:本来局部变量会被垃圾回收机制给回收的,但是我们给返回到外面了,并且在引用的情况下,是不回被回收的,会造成内存的一些浪费
4、call、apply、bind的区别是什么?
答:call、apply、bind三个为改变this指向的方法。
共同点:第一个参数都为改变this的指针。若第一参数为null/undefined,this默认指向window
区别:call(无数个参数)参数是一个一个传递。第一个参数:改变this指向;第二个参数:实参;使用之后会自动执行该函数

function fn(a,b,c){
        console.log(this,a+b+c); // this指向window
    }
    fn();
    fn.call(document,1,2,3);//call改变之后this指向document  
    //输出 #document 6   1,2,3是实参 结果相加为6

apply(两个参数)是把所有参数组成一个数组传递。第一个参数:改变this指向;第二个参数:数组(里面为实参);使用时候会自动执行函数

function fn(a,b,c){
        console.log(this,a+b+c); 
    }
    fn();
    fn.apply(document,[1,2,3]); 

bind(无数个参数),第一个参数:改变this指向;第二个参数之后:实参;返回值为一个新的函数

function fn(a,b,c){
    console.log(this,a+b+c); //window
}
let ff = fn.bind('小明',1,2,3); //手动调用一下

使用的时候需要手动调用下返回 的新函数(不会自动执行)
5、请指出js宿主对象(host object)和原生对象(native object)的区别?
答:宿主对象是指DOM和BOM;宿主对象不是引擎的原生对象,是宿主框架通过某种机制注册到js引擎里的对象。
原生对象是指Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、Math等对象。除了内置对象,还有一些在运行过程中创建出的对象。
6、请指出下面代码的区别:function person()、var person = Parson()、var person = new Person()。
答:function person():声明一个person函数,this指向window;var person = Parson():将Parson方法返回的结果给person变量,如果没有返回值则是undefined,this指向person;var person = new Person():创建一个构造函数,this指向Person。
7、请解释变量声明提升
答:举一个例子:

foo(2);

function foo(a){
  console.log(a);
}

编译阶段:1、先遇见了foo(2),一个函数执行,不是我编译器的活,略过。2、发现了function,告诉JS引擎编译器有函数要声明,需要在当前作用域内的内存中开辟一块空间给foo,继续编译函数内部(从上到下一行一行编译),遇到形参a后在函数内存里开辟一块空间给a,只不过现在a的值为undefined,继续走,结束。
执行阶段:1、遇到了foo(2),引擎:作用域,你见过foo没?作用域:见过,刚才编译器那小子刚声明了他,我给你。引擎:好的。那我来执行以下foo这个函数。作用域兄弟,你在foo中见过a吗?作用域:有,编译器也声明他了,给你。引擎:谢了哥们,我把2复制给他。
来一个测试题

var a = new Object();
a.param = 123;

function foo(){
  get = function(){
      console.log(1);
  };
  return this;
}

foo.get = function(){
  console.log(2);
};

foo.prototype.get = function(){
  console.log(3);
};

var get = function(){
  console.log(4);
};

function get(){
  console.log(5);
}

foo.get();
get();
foo().get();
get();
new foo.get();
new foo().get();
new new foo().get();
// 2,4,1,1,2,3,3

8、什么是use strict?使用它的好处和坏处分别是什么?
答:只要在js文件的第一行加上use steict就是开启严格模式,严格模式下的this不是指向window,指向的是undefined,帮助我们养成良好的代码习惯,有一些不严谨的代码会报错。
9、什么是事件循环(event loop)?
js是单线程的,也就是说一个时间只能做一件事,做什么事都要排队,想要同一时间做多件事情,这就衍生出了异步,将事件放在消息队列里,先执行可以直接执行的操作,之后不停的去询问消息队列:有没有要执行的?如果有就取出来放到主线程里执行,如果没有就继续之前的操作。举个例子:

console.log('start')

setTimeout(function() {
    console.log('setTimeout')
}, 0)

console.log('end')
// start
// end
// setTimeout

在上述的例子中两个console是同步代码,所以直接进入主线程的执行栈中执行,setTimeout是异步代码所以放到消息队列里。在执行栈中按照代码从上到下的执行顺序,打印 start => end。执行栈中的任务全部完成后,对消息队里进行轮询,由于定时器设定的时间为0,所以会在执行栈的任务清空后立即执行,所以上述例子的打印结果为start => end => setTimeout

大致总结js事件线程循环的过程:
1、所有任务都在主线程上执行,形成一个执行栈。
2、所有执行栈中的所有同步任务执行完毕,js就会读取息队列中的异步任务,如果有可以执行的任务就把他放在执行栈中并开始执行。
3、主线程不断重复上面第二步,这样的一个循环成为事件循环。
js事件循环中有异步队列有两种:宏任务队列(macro)和微任务队列(micro)
常见的宏任务比如:setTimeout、setInterval、 setImmediate、script(整体代码)、 I/O 操作、UI 渲染等。
常见的微任务比如:process。nextTick、Pormise、MutationObserver 等。
eventLoop循环过程:
1、初始状态:微任务队列只有一个script脚本;(整体代码为宏任务)
2、【宏任务阶段】执行script代码,创建宏任务到宏任务调用栈中,创建的微任务到微任务调用栈中。
3、【微任务阶段】执行微任务,调出当前微任务中的所有微任务,一次性执行,其中如果有宏任务推到宏任务栈中。
4、【宏任务阶段】执行宏任务,调用当前宏任务栈中的第一个宏任务,其中有创见的微任务推到微任务栈中。
5、如果代码没结束,循环执行3、4步骤。
总结:
1、宏任务和微任务是交替进行的
2、每个宏任务只执行栈中的第一个任务,执行完就执行微任务。微任务执行栈中所有的微任务。

console.log('sync');
 
setTimeout(function () {
   console.log('setTimeout')
}, 0);
 
var promise = new Promise(function (resolve, reject) {
   console.log('promise');
   setTimeout(function() {
      promise.then(function(){
        console.log('promise-setTimeout-then')    
      })
      console.log('promise-setTimeout')
   }, 0);
   resolve();
});
 
promise.then(function() {
    setTimeout(function() { 
            promise.then(function(){
                console.log('then-setTimeout-then')    
            })
            console.log('then-setTimeout')
    }, 0);
    console.log('then');
    promise.then(function(){
        console.log('then-than')    
    })
})
////宏任务阶段
sync  
promise
//微任务阶段
then
then - than
//宏任务阶段
setTimeout
//微任务阶段(没有任务,没有输出)
//宏任务阶段
promise - setTimeout
//微任务阶段
promise - setTimeout - then
//宏任务阶段
then - setTimeout
//微任务阶段
then-setTimeout-then

如果不清楚请跳转链接:https://blog.csdn.net/webjhh/article/details/116759051
10、请解释同步和异步的区别。
11、http的状态码
答:1信息,服务器接收到请求,请求者继续吧
2
成功。
3重定向,需要进一步操作来完成请求
4
客户端错误
5**服务端错误
16、浏览器的垃圾回收机制是什么?
12、构造函数new的过程
1、创建一个新对象
2、把当前构造函数的作用域给新的对象(此时this指向就会指向新对象)
3、执行构造函数中的代码(给新的对象添加方法或者是属性)
4、返回新对象
通过new关键字创建的对象会有一个constructor属性,该属性指向的是当前的这个对象。
注意:原本构造函数是window对象的方法,如果不是用new调用,那么指向的还是window,那么this指向也是window。如果是用new关键字调用,那么this指向就是当前的对象。
13、如果后端给前端一个很大的数,前端要怎么处理?
答:分页,滚动加载,加lodding,节流。
14、函数的节流和防抖
函数节流是指一定时间内js方法只跑一次
函数防抖是指频繁触发的情况下,只有足够的空闲时间,才执行代码一次。
函数防抖的要点,也是需要一个setTimeout来辅助实现。延迟执行需要跑的代码。
如果方法多次触发,则把上次记录的延迟执行代码用clearTimeout清掉,重新开始。
如果计时完毕,没有方法进来访问触发,则执行代码。

上一篇下一篇

猜你喜欢

热点阅读