2021年这些js相关的前端面试题真的值得收藏(一)

简介: 2021年这些js相关的前端面试题真的值得收藏

1. 实用js写红绿灯的效果?

<ul id="traffic" class="">
 <li id="green"></li>
 <li id="yellow"></li>
 <li id="red"></li>
</ul>
ul {
 position: absolute;
 width: 200px;
 height: 200px;
 top: 50%;
 left: 50%;
 transform: translate(-50%,-50%);
}
 /*画3个圆代表红绿灯*/
 ul >li {
  width: 40px;
  height: 40px;
  border-radius:50%;
  opacity: 0.2;
  display: inline-block;
 }
 /*执行时改变透明度*/
 ul.red >#red, 
 ul.green >#green,
 ul.yellow >#yellow{
  opacity: 1.0;
 }
 /*红绿灯的三个颜色*/
 #red {background: red;}
 #yellow {background: yellow;}
 #green {background: green;}
function timeout(timer){
  return function(){ 
   return new Promise(function(resolve,reject){
   setTimeout(resolve,timer) 
   })  
  }
  }
 var green = timeout(3000);
 var yellow = timeout(4000);
 var red = timeout(5000);
 var traffic = document.getElementById("traffic");
 (function restart(){
  'use strict'      //严格模式
  console.log("绿灯"+new Date().getSeconds()) //绿灯执行三秒 
  traffic.className = 'green';
  green()
  .then(function(){
   console.log("黄灯"+new Date().getSeconds()) //黄灯执行四秒
   traffic.className = 'yellow';
   return yellow();
  })
  .then(function(){
   console.log("红灯"+new Date().getSeconds()) //红灯执行五秒
   traffic.className = 'red';
   return red();
  }).then(function(){
   restart()
  })
  })();

2. axios是否需要promise封装?

需要

import axios from 'axios'
const http = ({
  url,method,params,headers
}) => {
return new Promise ( (resolve,reject) => {
  axios({
    url,
    method,
    params,
    headers
  })
  .then( res => {
    resolve(res)
  })
  .catch( error => {
    throw error
  })
  })
}
export default http

3. Promise内部发生错误,如果同时.then方法有第二个参数,也有.catch会调用哪个

.catch

4. 宏任务 微任务

setTimeout(function(){
        console.log('1')
    });
    new Promise(function(resolve){
        console.log('2');
                    resolve();
    }).then(function(){
        console.log('3')
    });
    console.log('4')

settimeout肯定是异步的。 我也知道有一个event队列,你settimeout没设置时间应该直接就进入这个队列了吧,然后就是Promise的回掉函数进入event队列。 当时我二话不说给了个答案 2,4,1,3.并且很自信。然后面试官就问你不想想了?我说不想了。然后后半段他全程开始皱眉头了。我也凉凉。最后他让我回去看一下宏任务和微任务。


首先说一下普通的异步函数的执行过程吧


同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。当指定的事情完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的Event Loop(事件循环)。


那么如此看来我给的答案还是对的。但是js异步有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入eventqueue,然后在执行微任务,将微任务放入eventqueue最骚的是,这两个queue不是一个queue。当你往外拿的时候先从微任务里拿这个回掉函数,然后再从宏任务的queue上拿宏任务的回掉函数。 我当时看到这我就服了还有这种骚操作。


而宏任务一般是:包括整体代码script,setTimeout,setInterval。


微任务:Promise,process.nextTick。


记住就行了。


然后回到开头的代码。因为settimeout是宏任务,虽然先执行的他,但是他被放到了宏任务的eventqueue里面,然后代码继续往下检查看有没有微任务,检测到Promise的then函数把他放入了微任务序列。等到主线进程的所有代码执行结束后。先从微任务queue里拿回掉函数,然后微任务queue空了后再从宏任务的queue拿函数。


所以正确的执行结果当然是:2,4,3,1。


https://juejin.im/post/59e85eebf265da430d571f89


5. Js 原型和原型链


原型链的设计是js的精髓所在,比较抽象。需要从内部设计原理去理解这种设计思想,在纸上画画其中的关系会帮助理解。


prototype对象


prototype对象的引入:所有实例对象需要共享的属性和方法,都放在这个对象中,那些不需要共享的属性和方法,就放在构造函数中。以此来模拟类。


function Animal(name) {
    this.name = name
}
Animal.prototype.getName = function() {
    console.log(this.name)
}
var animal1 = new Animal('Kate')
var animal2 = new Animal('Lucy')
//对象animal1 和 animal2共享方法getName
animal1.getName()
animal2.getName()

原型链


在javascript中,每个对象都有一个指向它的原型(prototype)对象的内部链接。每个原型对象又有自己的原型,直到某个对象的原型为null为止,组成这条链的最后一环。


*proto写入es6标准


当一个对象被创建时,它的__protp__属性和内部属性[[prototype]]指向相同的对象(也就是它的构造函数的prototype属性)。改变__proto__属性的值同时也会改变内部属性[[prototype]]的值,除非该对象是不可扩展的。

在ES5中,所有构造函数的__proto__都指向Function.prototype

**在ES6中,构造函数的__proto__指向它的父类构造函数

obj.__proto__ === obj.[[prototype]]
// ES5
Cat.__proto__ === Function.prototype
// ES6
Cat.__proto__ === Animal

构造函数继承

有四种方式可以实现构造函数的继承

1.调用apply方法

function Animal() {
    this.species = '动物'
}
Animal.prototype.getName = function() {
    console.log('我是动物')
}
function Cat() {
    Animal.apply(this, arguments)
}
var cat = new Cat()
cat.species    // 动物
cat.getName()  // undefined

这种方法可以继承父类构造函数的属性,但是无法继承prototype属性,即父类中共享的方法和属性

2.改写prototype对象

Cat.prototype = new Animal()
Cat.prototype.constructor = Cat

这是最常用的方法来模拟单继承,缺点是始终要保留Animal的对象,如果Animal对象比较大时,会消耗部分内存(其实很少),并且没有实现多继承


3.直接继承prototype

Cat.prototype = Animal.prototype
Cat.prototype.constructor = Cat

缺点是当修改了Cat.prototype上的方法时会影响Animal.prototype

4.利用空对象作中介

var F = function(){}
F.prototype = Animal.prototype
Cat.prototype = new F()
Cat.prototype.constructor = Cat

6. js的事件循环机制是什么

进程、线程


进程是系统分配的独立资源,是 CPU 资源分配的基本单位,进程是由一个或者多个线程组成的。

线程是进程的执行流,是CPU调度和分派的基本单位,同个进程之中的多个线程之间是共享该进程的资源的。


浏览器内核


浏览器是多进程的,浏览器每一个 tab 标签都代表一个独立的进程(也不一定,因为多个空白 tab 标签会合并成一个进程),浏览器内核(浏览器渲染进程)属于浏览器多进程中的一种。


浏览器内核有多种线程在工作。


GUI 渲染线程:


负责渲染页面,解析 HTML,CSS 构成 DOM 树等,当页面重绘或者由于某种操作引起回流都会调起该线程。

和 JS 引擎线程是互斥的,当 JS 引擎线程在工作的时候,GUI 渲染线程会被挂起,GUI 更新被放入在 JS 任务队列中,等待 JS 引擎线程空闲的时候继续执行。

JS 引擎线程:


单线程工作,负责解析运行 JavaScript 脚本。

和 GUI 渲染线程互斥,JS 运行耗时过长就会导致页面阻塞。

事件触发线程:


当事件符合触发条件被触发时,该线程会把对应的事件回调函数添加到任务队列的队尾,等待 JS 引擎处理。

定时器触发线程:


浏览器定时计数器并不是由 JS 引擎计数的,阻塞会导致计时不准确。

开启定时器触发线程来计时并触发计时,计时完成后会被添加到任务队列中,等待 JS 引擎处理。

http 请求线程:


http 请求的时候会开启一条请求线程。


请求完成有结果了之后,将请求的回调函数添加到任务队列中,等待 JS 引擎处理。


JavaScript 引擎是单线程


JavaScript 引擎是单线程,也就是说每次只能执行一项任务,其他任务都得按照顺序排队等待被执行,只有当前的任务执行完成之后才会往下执行下一个任务。


HTML5 中提出了 Web-Worker API,主要是为了解决页面阻塞问题,但是并没有改变 JavaScript 是单线程的本质。了解 Web-Worker。


JavaScript 事件循环机制


JavaScript 事件循环机制分为浏览器和 Node 事件循环机制,两者的实现技术不一样,浏览器 Event Loop 是 HTML 中定义的规范,Node Event Loop 是由 libuv 库实现。这里主要讲的是浏览器部分。


Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。


JS 调用栈


JS 调用栈是一种后进先出的数据结构。当函数被调用时,会被添加到栈中的顶部,执行完成之后就从栈顶部移出该函数,直到栈内被清空。


同步任务、异步任务


JavaScript 单线程中的任务分为同步任务和异步任务。同步任务会在调用栈中按照顺序排队等待主线程执行,异步任务则会在异步有了结果后将注册的回调函数添加到任务队列(消息队列)中等待主线程空闲的时候,也就是栈内被清空的时候,被读取到栈中等待主线程执行。任务队列是先进先出的数据结构。


Event Loop


调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了,这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,就形成了事件循环。


7.前端跨域的方式


前端跨域的方案:
1、通过jsonp跨域
2、postMessage跨域
3、跨域资源共享(CORS)
4、nginx代理跨域
5、nodejs中间件代理跨域
6、WebSocket协议跨域
7.反向代理
<u>https://segmentfault.com/a/1190000011145364</u>
相关文章
|
9天前
|
JavaScript 前端开发 API
详解队列在前端的应用,深剖JS中的事件循环Eventloop,再了解微任务和宏任务
该文章详细讲解了队列数据结构在前端开发中的应用,并深入探讨了JavaScript的事件循环机制,区分了宏任务和微任务的执行顺序及其对前端性能的影响。
|
7天前
|
JavaScript 前端开发 小程序
一小时入门Vue.js前端开发
本文是作者关于Vue.js前端开发的快速入门教程,包括结果展示、参考链接、注意事项以及常见问题的解决方法。文章提供了Vue.js的基础使用介绍,如何安装和使用cnpm,以及如何解决命令行中遇到的一些常见问题。
一小时入门Vue.js前端开发
|
7天前
|
Web App开发 前端开发 Linux
「offer来了」浅谈前端面试中开发环境常考知识点
该文章归纳了前端开发环境中常见的面试知识点,特别是围绕Git的使用进行了详细介绍,包括Git的基本概念、常用命令以及在团队协作中的最佳实践,同时还涉及了Chrome调试工具和Linux命令行的基础操作。
「offer来了」浅谈前端面试中开发环境常考知识点
|
9天前
|
JavaScript 前端开发 开发者
深入浅出 Vue.js:构建响应式前端应用
Vue.js 是一个流行的前端框架,以其简洁、高效和易学著称。它采用响应式和组件化设计,简化了交互式用户界面的构建。本文详细介绍 Vue.js 的核心概念、基本用法及如何构建响应式前端应用,包括实例、模板、响应式数据和组件等关键要素,并介绍了项目结构、Vue CLI、路由管理和状态管理等内容,帮助开发者高效地开发现代化前端应用。
|
9天前
|
JavaScript 前端开发
网页前端课程设计-【模仿】香港中文大学官网,轮播图及div+css布局,js的dom操作
这篇文章介绍了如何模仿香港中文大学官网进行网页前端课程设计,包括使用div+css布局、js的DOM操作以及实现轮播图等技术细节。
|
10天前
|
前端开发 JavaScript
前端JS控制网页复制粘贴
前端JS控制网页复制粘贴
|
2月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
2月前
|
Java C++
【Java基础面试十七】、Java为什么是单继承,为什么不能多继承?
这篇文章讨论了Java单继承的设计原因,指出Java不支持多继承主要是为了避免方法名冲突等混淆问题,尽管Java类不能直接继承多个父类,但可以通过接口和继承链实现类似多继承的效果。
【Java基础面试十七】、Java为什么是单继承,为什么不能多继承?
|
2月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
2月前
|
Java
【Java基础面试三十七】、说一说Java的异常机制
这篇文章介绍了Java异常机制的三个主要方面:异常处理(使用try、catch、finally语句)、抛出异常(使用throw和throws关键字)、以及异常跟踪栈(异常传播和程序终止时的栈信息输出)。
下一篇
无影云桌面