【面试题系列】必须掌握的六大类型JS面试题

这篇具有很好参考价值的文章主要介绍了【面试题系列】必须掌握的六大类型JS面试题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🐱 个人主页:不叫猫先生,公众号:前端舵手
🙋‍♂️ 作者简介:2022年度博客之星前端领域TOP 2,前端领域优质作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!
💫优质专栏:vue3+vite+typeScript从入门到实践
📢 资料领取:前端进阶资料可以找我免费领取
🔥 摸鱼学习交流:我们的宗旨是在「工作中摸鱼,摸鱼中进步」,期待大佬一起来摸鱼(文末有我wx或者私信)。

1、原型和原型链

当我们找实例对象的属性时,如果找不到,就会查找与对象关联的原型中去找,如果还找不到,就去找原型的原型,直到最顶层。

function A() {}
function B(a) {
    this.a = a;
}
function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
console.log(new A().a);
console.log(new B().a);
console.log(new C(2).a);

答案:1 undefined 2

解析:


//声明一个构造函数A
function A() {}
//声明一个构造函数B,传人参数a,自有属性a的值取决于传入的参数
function B(a) {
    this.a = a;
}
//声明一个构造函数B,如果有参数,则添加自有属性a,属性a的值为传入的参数值,
//如果没有传入参数,则构造函数C没有自有属性
function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
//构造函数function A(){},是没有自有属性的,然后就会顺着原型链查找,我们找到构造函数A的原型对象A.prototype上有属性a且等于1
console.log(new A().a);//1
console.log(new B().a);//undefined
console.log(new C(2).a);//2

2、异步队列

微任务:Promise.then、async/await、MutaionObserver
宏任务:script(整体)、setTimeout、setInterval、Ajax、DOM事件、postMessage
执行顺序如下:
【面试题系列】必须掌握的六大类型JS面试题

  • 第一题
  async function async1() {
    console.log("a");
    const res = await async2();
    console.log("b");
   }
    async function async2() {
     console.log("c");
     return 2;
    }

    console.log("d");
    setTimeout(() => {
      console.log("e");
    }, 0);
    async1().then(res => {
    console.log("f")
    })
    new Promise((resolve) => {
      console.log("g");
      resolve();
    }).then(() => {
    console.log("h");
    });
  console.log("i");

答案:d、a、c、g、i、b、h、f、e

解析:

//打印d
//遇到setTimeout,放到宏任务队列
//遇到async1().then(),先执行async1(),then函数注册到微任务队列(但不是立即注册,而是等async1()执行完之后才会注册)
//在执行async1()时候
  async1().then(res => {
      console.log("f")
  })
//打印a
//执行async1()时,当执行到 const res = await async2()时,await后先让后面的表达式先执行,也就是async2()
//打印c
//然后将其后面的代码放到微任务队列中,然后跳出async函数,执行后面的代码,console.log("c")被放到了微任务队列中
//执行new Promise((resolve) => { console.log("g"); resolve();  }).then(),由于new Promise()是同步任务
//打印g
//new Promise后的then函数放到微任务队列
//打印i
//此时微任务队列[console.log("b"),console.log("h")][console.log("f")]
//宏任务队列[console.log("e")]
//先执行微任务,再执行宏任务
//打印g、f、e
  • 第二题
setTimeout(function(){
    console.log(1)
  },0)

  new Promise(function(resolve,reject){
      console.log(2)
      for(var i=0;i<10000;i++) {
          if(i===10){
              console.log(10);
          }
          i==9999 && resolve()
      }
      console.log(3);
  }).then(function(){
      console.log(4);
  })
  console.log(5);

答案:2 10 3 5 4 1

解析文章来源地址https://www.toymoban.com/news/detail-479372.html

//setTimeout放到宏任务队列
//执行 new Promise()同步任务
//打印2
//打印10
//打印3
// new Promise()后的then函数 放到微任务队列
//打印5
微任务队列:[console.log(4)]
宏任务队列:[ console.log(1)]
  • 第三题
Promise.reject(1).
			then(2).
			then(res => { return 3 }).
			catch(error => { return 4 }).
			then(Promise.resolve(5)).
			then(console.log)

答案:4
解析:

//Promise.reject(1) 返回一个被拒绝的 Promise,其拒绝原因为数字 1。
//.then(2) 返回一个新的 Promise,它的回调函数不会被调用,因为前一个 Promise 被拒绝了。
//.then(res => { return 3 }) 返回一个新的 Promise,它的回调函数也不会被调用,因为前一个 Promise 被拒绝了。
//.catch(error => { return 4 }) 返回一个新的 Promise,它的回调函数被调用并返回数字 4(作为一个被解决的 Promise)。
//.then(Promise.resolve(5)) 返回一个新的 Promise,它的回调函数不会被调用,因为参数不是一个函数。
//.then(console.log) 返回一个新的 Promise,它的回调函数被调用并打印数字 4。
  • 第四题
var F = function() {};
Object.prototype.a = function() {
  console.log("a()");
};
Function.prototype.b = function() {
  console.log("b()");
};
var f = new F();
F.a();
F.b();
f.a();
f.b();

答案:a b a f.b is not a function

解析:

//1、声明变量F,F既是对象也是函数,故F可调用原型上的方法,无论是对象还是函数上的
//2、f = new F(),通过 构造函数 F new了一个实例f,此f只是一个对象并不是函数类型,故不能调用Function原型上的方法
//证明:

【面试题系列】必须掌握的六大类型JS面试题

3、浅拷贝/深拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
深拷贝生成一个新对象,新对象跟原对象不共享内存,修改新对象不会改到原对象

  • 第一题
var obj1 = {
    a:  1,
    b:  2,
    c:  3
}
var obj2 = obj1;
obj2.a = 5;
console.log(obj1.a);  
console.log(obj2.a);

答案:1 5

解析

//var obj2 = obj1属于浅拷贝,故而obj1,obj2共用一个内存,打印出5,5
  • 第二题
var obj1 = {
a: 1,
b: 2,
c: 3
}
var objString = JSON.stringify(obj1);
var obj2 = JSON.parse(objString);
obj2.a = 5;
console.log(obj1.a);
console.log(obj2.a);

解析

//JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串
//JSON.parse() 方法用来解析 JSON 字符串,解析为 JavaScript 值或对象
//JSON.parse(JSON.stringify())也常被用作深拷贝
//深拷贝生成一个新对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
//打印1、5
  • 第三题
       let obj = {
			num: 117
		}
		var num = 935;
		function func() {
			console.log(this.num)
		}
		const wrapper = func.bind(obj);
		setTimeout(() => {
			wrapper()
		}, 1000)
		obj = {
			num: 130
		}

答案:117

解析:

//在执行const wrapper = func.bind(obj)时,func的this指向obj
//接着执行setTimeout,1s后执行wrapper
//在上面的一秒内,重新赋值obj = {num:130},这并不会影响到已经绑定了 obj 的 wrapper 函数
//所以打印出117

4、作用域

JS代码的执行是由浏览器中的JS解析器来执行的。JS解析器执行JS代码的时候,分为两个过程:预解析过程,代码执行过程预解析过程:

1、把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
2、把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
3、先提升var,在提升function。

预解析顺序:

1、预解析的顺序是从上到下,函数的优先级高于变量,函数声明提前到当前作用域最顶端,在var之上。
2、函数执行的时候,函数内部才会进行预解析,如果有参数,先给实参赋值再进行函数内部的预解析。
3、预解析函数是声明+定义(开辟了内存空间,形参值默认是undefined)。
4、预解析变量是只声明,不赋值,默认为undefined。
5、函数重名时,后者会覆盖前者。
6、变量重名时,不会重新声明,但是执行代码的时候会重新赋值。
7、变量和函数重名的时候,函数的优先级高于变量

函数执行顺序:

1、形成私有作用域
2、形参赋值(也是私有变量)
3、变量提升
4、代码从上到下执行
5、作用域是否销毁

函数作用域不销毁的条件:

1、函数的返回值为引用类型
2、返回值被其他变量使用

  • 第一题
var a = 0, b = 0
function A(a) {
  A = function(b) {
    console.log(a + b++)
  }
  console.log(a++)
}
A(1)
A(2)

答案:2 4

解析

//执行A(1),传入参数1
//修改函数A的值为:function(b) { console.log(a + b++) }
// 执行 console.log(a++),打印出1

//执行A(2),传入参数2
//由于A函数被修改,所以执行的的是function(b) { console.log(a + b++) }
// 此时a为2,传入的b为2 ,所以打印4
  • 第二题
console.log(a);  
var a=12;
function fn(){
		console.log(a);
        a=13;
	}	
	
fn();
console.log(a); 

答案:undefined 12 13

解析:

//如果在函数中定义变量时,如果不添加var关键字, 这个变量是一个全局变量 
//打印undefined
//由于a=13在定义a变量没有用关键字,所以在这里是全局变量
//fn执行console.log(a)时没有找到私有变量a,会沿着作用域链查找变量
//打印12
//紧接着a=13修改全局变量
//打印13
  • 第三题

console.log(a); 
a=2;
function fn(){
		console.log(a);
		a=3;	
	}	
	
fn();
console.log(a);

答案:Uncaught ReferenceError: a is not defined

解析:

//变量a不会被提升,因为没有var声明,
//如果在函数中定义变量时,如果不添加var关键字, 这个变量是一个全局变量 
//所以会报错:Uncaught ReferenceError: a is not defined
  • 第四题

var a=10,b=11,c=12;
   
function test(a){
        a=1;var b=2;c=3;
   }  
 
test(10);
alert(a);  alert(b);   alert(c); 

答案:1 11 3

  • 第五题
var foo = function () {
    console.log("foo1")
}
foo()

var foo = function () {
    console.log("foo2")
}
foo()


function foo() {
    console.log("foo1")
}
foo()

function foo() {
    console.log("foo2")
}
foo()

答案:foo1 foo2 foo2 foo2

解析:

//该题可以把代码分开
var foo = function () {
    console.log("foo1")
}
foo()

var foo = function () {
    console.log("foo2")
}
foo()

//1、声明了变量foo,因为声明变量重名了,故不会重新声明,
//2、执行代码时候,会先执行
function () {
    console.log("foo1")
}
//3、又对变量进行重新复制,故执行
function () {
    console.log("foo2")
}
//所以打印出 foo1 foo2
----------------------------------------
function foo() {
    console.log("foo1")
}
foo()

function foo() {
    console.log("foo2")
}
foo()
//1、在预解析的时候,由于声明函数foo重名,故后者会覆盖前者,所以最后foo函数声明的结果如下
function foo() {
    console.log("foo2")
}
//2、执行打印出foo2 foo2

5、矩阵转置

将 [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]——>[ [1, 4, 7], [2, 5, 8], [3, 6, 9] ]

let a = [
  [123],
  [456],
  [789]
]
let b = [
  [147],
  [258],
  [369]
]
//其实不难发现 a[0][0] = b[0][0],a[0][1] = b[1][0],a[0][2] = b[2][0]
//也就是 a[i][j] = b[j][i]

解析:

function transposeArray(array) {
	// 获取原行数和列数 
	const rows = array.length;
	const cols = array[0].length;
	 // 创建一个新的二维数组,长度等于原来数组列数
	const transposedArray = [];
	for (let j = 0; j < cols; j++) {
		transposedArray[j] = new Array(rows);
	}
	// 将元素从原数组复制到新数组中 
	for (let i = 0; i < rows; i++) {
		for (let j = 0; j < cols; j++) {
			transposedArray[j][i] = array[i][j];
		}
	}
	return transposedArray;
}
const myArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
const transposedArray = transposeArray(myArray);
console.log(transposedArray);
// 输出:[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

6、类、继承

     	class cls{
			constructor(){
				this.show()
			}
			show(){
				console.log("yoo")
			}
		}
		class son extends cls{
			constructor(){
				super()
			}
			show(){
				console.log('ohh')
			}
		}
		new son()
		new cls()

答案:ohh yoo

解析

//1、在创建 son 对象时,会先调用父类 cls 的构造函数
//2、然后再调用子类 son 的构造函数。
//3、在子类 son 的构造函数中,没有显式调用父类的 show 方法,因此会直接执行子类中重写的 show 方法,输出 “ohh”。
//4、接着创建 cls 对象时,同样会调用父类 cls 的构造函数,执行父类的 show 方法,输出 “yoo”

7、this指向

  • 第一题
    百度一面面试题
window.length = 111;
function fn() {
    console.log(this.length,this)
}

const o = {
    length: 222,
    a: function (fn) {
        fn();
        arguments[0]();
        console.log(this.length);
    }
}
o.a(fn, 2);

答案:111 2 222

解析

o.a(fn, 2)执行时,fn()调用时,this执行window,所以打印为111。
arguments[0]()调用时,arguments为[fn,2],arguments[0]也就是执行的是fn,arguments[0]()也相当于arguments.[0](),所以执行fn时this指向arguments,故打印出2。
console.log(this.length),this指向对象o,所以打印出222

到了这里,关于【面试题系列】必须掌握的六大类型JS面试题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 程序员面试系列,golang常见面试题

    原文链接 make(chan int, 1) 和 make(chan int) 之间有区别。 make(chan int, 1) 创建了一个有缓冲的通道,容量为1。这意味着通道可以缓存一个整数元素,即使没有接收方,发送操作也不会被阻塞,直到通道已满。如果没有接收方,发送操作会立即完成。如果通道已满,发送操作会被阻塞

    2024年02月16日
    浏览(45)
  • 程序员面试系列,docker常见面试题

    原文链接 什么是Docker?它的主要作用是什么? Docker和虚拟机之间有什么区别? Docker的主要组件有哪些? Docker镜像和容器的区别是什么? 如何构建Docker镜像?请简要描述构建过程。 如何创建和启动一个Docker容器? 如何在Docker容器内运行后台任务? Docker的网络模式有哪些?

    2024年02月15日
    浏览(43)
  • 程序员面试系列,kafka常见面试题

    原文链接 Kafka是什么?它的主要作用是什么? 什么是Kafka的主题(Topic)和分区(Partition)? Kafka中的消息是如何被生产者发送和消费者接收的? Kafka中的分区有什么作用?为什么分区是Kafka的基本并行单位? 什么是Kafka生产者和消费者?如何创建和配置它们? Kafka中的消息保

    2024年02月15日
    浏览(45)
  • 程序员面试系列,k8s常见面试题

    原文链接 Kubernetes(通常简称为K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它最初由谷歌开发,并于2014年捐赠给了云原生计算基金会(CNCF)。Kubernetes 提供了一个强大的容器化应用程序管理系统,使开发人员和运维团队能够更轻松地构建

    2024年02月06日
    浏览(46)
  • 吊打面试官系列之:什么是 认证、鉴权、授权、权限控制,这一篇必须安排的明明白白。

    小屌丝 :鱼哥,啥是认证,啥是鉴权? 小鱼 :嗯?? 做了这么多年码农,这个还不知道呢? 小屌丝 :唉~~ 没整明白啊,能不能给我讲一讲啊 小鱼 :好吧,正好今晚有时间,我就把 认证、鉴权、授权及权限控制这点事,都给你说一说。 小屌丝 :奈斯啊。 定义:

    2024年02月04日
    浏览(48)
  • Js面试之数据类型相关

    最近在整理一些前端面试中经常被问到的问题,分为vue相关、react相关、js相关、react相关等等专题,可持续关注后续内容,会不断进行整理~ Javascript的数据类型是一个基础考点,本文总结相关面试题: 基本数据类型包括:Number、String、Boolean、Null、Undefined、Symbol(Es6新增),

    2024年01月18日
    浏览(79)
  • 程序员必须掌握哪些算法?

    算法是我非常注重学习的一门知识 。下面是我觉得值得学习的一些算法以及数据结构,当然, 并且我也整理一些看过不错的文章给大家, 大家也可以留言区补充。如果觉得不错,别忘了点个赞哦。先上图,后详细解说 一、算法最最基础 1、时间复杂度 2、空间复杂度 一般最

    2024年02月07日
    浏览(57)
  • 【程序员必须掌握哪些算法?】

    一个程序员一生中可能会邂逅各种各样的算法,但总有那么几种,是作为一个程序员一定会遇见且大概率需要掌握的算法。今天就来聊聊这些十分重要的“必抓!”算法吧~ 本文所介绍的排序算法均以升序为例。 直接插入排序是从一段数据中将一个数据在合适的位置插入。

    2024年02月17日
    浏览(64)
  • CSS基础知识,必须掌握!!!

    CSS背景属性用于定义HTML元素的背景 CSS属性定义背景效果: background-color - 定义背景颜色 background-image - 定义背景图片 background-repeat - 是否平铺,水平平铺(repeat-x)、垂直平铺(repeat-y)、不平铺(no-repeat) background-attachment - 是否固定背景图片,不随滚动而发生位置改变 bac

    2023年04月09日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包