js八股文

面试题:
1.作用域和执行上下文?
全局作用域---->预解析(var变量和函数提升)--->全局执行上下文环境--->全局的变量对象{var ,function ,函数参数,this的指向}----->函数定
义---->局部作用域---->出现了函数调用----->局部预解析--->局部的执行上下文环境---->局部的变量对象{var ,function ,函数参
数,this的指向}
注意问题:函数中定义函数,内部函数没有调用,则不会出现在局部执行上下文和变量对象
1)什么是作用域?
作用域是一块代码的地盘。
2)有什么作用
隔离变量,让不同作用域的变量不会冲突
3)作用域的分类
全局作用域
局部作用域
函数作用域 function () {}
块级作用域(ES6) if () {} / switch {} case / while () {} / for(){} ...
4) 作用域方向:是由内向外的,由小向大
5)作用域链:多个上下级关系的作用域形成的叫做作用域链
用来查找变量。先在自身作用域找,在找上一级作用域,直到全局作用域
如果某个作用域找到了,就不找了,如果在全局作用域都没找到,就会报错 xxx is not defined
2.原型链
1)讲讲原型和原型链?
1.原型实际上指的是两个原型对象:prototype 和 __proto__,prototype 叫做显示原型 __proto__ 叫做隐式原型
2.prototype显示原型:
所有函数都有prototype 和 __proto__。但是ES6中箭头函数没有prototype。
prototype上至少有两个内容:
constructor 函数构造方法,指向函数本身
__proto__ 指向 Object.prototype
__proto__指向Function.prototype
3.__proto__隐式原型(函数、数组也有):
所有对象都可以叫做实例对象,实例对象的__proto__指向其对应构造函数显示原型prototype属性(原型对象)
5.原型链:多个上下级prototype 和 __proto__的关系叫做原型链
它的作用用来查找对象上的属性的
先在自身找,再沿着隐式原型链一层层找,找到了就返回值
直到原型链的尽头 Object.prototype.__proto__ ,它的值为null,但是返回值为undefined
6.应用:用来实现继承,模拟面向对象
7.总结
1)函数上有prototype和__proto__,prototype上有constructor和__proto__
2)对象上有__proto__
3)对象上的__proto__指向其构造函数的prototype,构造函数的prototype的__proto__指向Object的prototype
Object的prototype的__proto__指向Null,,但是返回值为undefined
4)构造函数的__proto__指向Function的prototype的__proto__
2)js中继承方式有哪几种?
1、通过改变原型指向实现继承
将父类的实例作为子类的原型,这样父类在原型上新增的方法/属性,子类都能够访问
2、借用构造函数实现继承
通过call父类的构造函数,向构造函数传参来实现继承,但是构造继承只能继承父类实例的属性和方法,不能继承原型属性和方法,
3、组合继承
通过call调用父类构造函数,将父类的实例作为子类的原型,这样子类既可以继承父类实例的属性,也可以继承父类原型上的属性
6.寄生组合继承
4、拷贝继承
深拷贝:JSON.parse(JSON.stringify())等
浅拷贝:将对象直接赋值给一个变量等Object.assgin()
5.class继承
class定义类
extends继承父类
super调用父类构造函数
子类通过this可以使用父类的属性和方法
static定义类的方法 --> ES7 扩展定义类的属性
3)ES5的继承和ES6的继承有什么区别?
ES5的继承时通过prototype或构造函数机制来实现。ES5的继承实质上是先创建子类的实例对象,然后再将父类的方法添加到this上(Parent.apply(this))。
ES6的继承机制完全不同(extends和super),实质上是先创建父类的实例对象this(所以必须先调用父类的super()方法),然后再用子类的构造函数修改this。
具体的:ES6通过class关键字定义类,里面有构造方法,类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法,否则新建实例报错。因为子类没有自己的this对象,而是继承了父类的this对象,然后对其进行加工。如果不调用super方法,子类得不到this对象。
ps:super关键字指代父类的实例,即父类的this对象。在子类构造函数中,调用super后,才可使用this关键字,否则报错。
3)浅拷贝和深拷贝的区别?
浅拷贝:一般指的是把对象的第一层属性(应用地址)拷贝到一个新对象上去
深拷贝:一般需要借助递归实现,把一个对象的属性全部拿到另一个对象身上,并且完全替换掉每一个复杂类型的引用
4)this指向?
- 普通函数
- 函数直接调用 fn() --> window
- 在 ES5 严格模式下('use strict') --> undefined
- 定时器的回调函数:window
- 在 ES5 严格模式下('use strict') --> undefined
- 事件的回调函数:指向被绑定事件的 DOM 元素
- 特殊函数
- ES6 的箭头函数:指向离它最近,包裹它函数的 this(没有就是 window)
- 对象调用 obj.fn() --> obj
- ES6 类语法(class)中的方法:指向类的实例对象
3.事件循环机制
1)浏览器的事件环
所以的js代码都会在js主线程中执行,默认先在主线程中执行js的同步代码,碰到宏任务和微任务会放到宏任务和微任务队列中,等主线程中的同步代码执行完后会批量清空所有的微任务,
清空完微任务后开始渲染页面(这里并不会每次渲染,浏览器会有优化),渲染页面完开始拿出一个宏任务,循环前面步骤执行
2)宏任务与微任务
宏任务包括:scrip整体代码、setTimeout、setInterval、setImmediate、I/O操作、UI 渲染
微任务包括:process.nextTick、Promise、Async/Await、MutationObserver
3)node事件环
Node.js采用V8作为js的解析引擎,I/O处理使用自己设计的libuv库(下面的六个宏任务队列)。
1.timer 定时器队列
2.pending callback 除了i/o回调队列,每轮会执行一定个数的回调,剩下的回调会放到下一轮去执行,不可控
3.idle/preare 处理内部系统队列,不可控
4.poll 轮询队列,存放一些i/o回调队列,会在特定的时候进行阻塞
5.check 里面只放setImmediate队列
6.close callback 关闭回调队列
7.主要掌握timer/poll/check,浏览器的队列有多个,node的队列有多个
8.先会执行主线程的同步代码,再去执行微任务的process.nextTick()/promise.then(),再去执行其它微任务,接着会在自己设计的libuv队列按照顺序从上到下执行回调,最终回停留在poll阶段轮询执行i/o回调,
如果其它队列有回调执行(定时器等),先去执行了再在poll阶段轮询执行i/o回调
4)node事件环和浏览器事件环的区别
1.node中宏任务的循环是在自己设计的libuv库中,而浏览器的事件循环依赖以浏览器
2.node的微任务中也有优先级之分,process.nextTick()微任务队列高于其它的微任务队列
3.node没有渲染页面过程
3)dom事件机制
1)事件流:事件流是多个节点对象对同一个事件的响应顺序,事件流分为以下3个
冒泡型:(IE)
事件从最具体的目标(target)向最不特定的目标(document)触发,事件从里到外相应,被称作为冒泡
捕获型:(网景)
事件从最不具体的目标(document)开始触发,向最特定的目标结束,也就是从外向里响应。这样被称作为捕获
混合型:(W3C事件模型,事件机制,事件流)
W3C的事件模型支持冒泡和捕获类型,其中捕获过程先发生,目标阶段在执行,然后,冒泡阶段最后发生
开发人员可以选择W3C的事件执行时机
2)事件委托
就是我们平时绑定的事件,委托就是把目标节点的事件绑定到祖先元素上
3)mouseover 和 mouseenter的区别?
mouseover支持冒泡,mouseenter不支持冒泡
4.ES6/ES8/ES9
1)你用过哪些 ES6最新的语法?
let关键字/const关键字/解构赋值/模版字符串/简化对象的写法/箭头函数/三点运算符/形参默认值/class/for-of(遍历值)
2)promise对象知识点
1)怎么创建promise对象?
new Promise((resolve,reject)=>{})
Promise.resolve()
Promise.reject()
2) promise对象状态包括哪些?
1. pending 初始化状态(实例对象状态)
2. resolved 成功状态(实例中调用resolve,或者Promise.resolve() )
3. rejected 失败状态(实例中调用reject,或者Promise.reject() )
3)Promise解决的哪些问题
1.异步并发请求问题(Promise.all)
2.解决回调地狱问题(上一个的输出是下一个人的输入Promise.then)
3.错误处理非常方便 catch方法
4)Promise缺陷
依旧是基于回调函数,可读性必async和await差
5)原理
1)默认创建一个proimise 状态是pending,调用resolve状态变为resolved,调用reject状态变为rejected
2)调用成功和失败时 需要传递一个成功的原因和失败的原因,如果已经成功了就不能失败了,反之一样
3)每一个promise实例都有一个then方法,在then方法里面可以拿到原因和失败的原因,如果抛出异常按照失败来处理
4)then方法的异步执行
在调用then方法时将成功和失败回调放到实例的onResolvedCallbacks/onRejectedCallbacks队列中,当调用resolve()或reject()
方法再去执行队列里面的方法(订阅发布模式)
5)promise的链式调用
1.每次调用then都返回一个新的promise
2.如果then方法中(成功或者失败) 返回的不是一个promise,会将这个值传递给外层下一次then的成功结果
3.如果执行then方法中的方法出错了 抛出异常 会走到下一个then的失败
4.如果返回的是一个promise 会用这个promise的结果作为下一次then的成功或者失败
5.总结,抛出异常和返回失败promise走下一个then失败回调,否则走成功
6)resolve()方法
返回一个成功的promise对象,resolve()方法参数作为成功promise对象状态,在原型resolve()方法中val是promise对象要做继续递归解析
7)reject()方法
返回一个失败的promise对象,reject()方法参数作为失败promise对象状态
8)catch()方法
catch就相当于是一个then方法,只不过then的第一个参数是null
9)all()方法
返回值是一个新的promise对象,新promise对象状态看传入的promise
如果传入的promise状态都是成功的状态,新promise也成功,
内部的结果值,就是传入的promise成功状态内部的结果值(多个值用数组储存)
如果传入的promise状态有一个失败,新promise立即失败
内部的结果值,就是传入的promise失败状态内部的结果值(一个值)
10)race([promise1, promise2...])//那个先发生变化
返回值是一个新的promise对象,新promise对象状态看传入的promise
只看传入的n个promise,哪一个传入promise状态先发生变化
新promise和先发生变化promise的状态一致
内部的结果值,就是先发生变化的promise对象内部的结果值
11)Promise.allSettled([promise1, promise2...]) //等全部执行完 源自ES11/ES2020
返回值是一个新的promise对象,一定是成功状态(会等所以传入的promise状态发生改变在返回)
promise对象内部状态值,包含传入的n个promise对象的状态值 (以对象的形式储存)
10)finally()方法
无论这么样都会执行这个方法,参数是个回调函数,对调函数没有参数,回调函数可以返回一个promise,promise状态为成功不采用给下一次then()方法
promise状态为失败采用给下一次then()方法
2)generator函数(迭代器函数)
promise中有很多问题 内部还是采用回调的方式 ,如果逻辑过多代码可读性依旧比较差,我们希望写的代码更像同步一些,generator函数可以解决这个问题
// yield表示的是产出, *代表的是generator函数
// 内部是根据指针+switch+case来实现
// babel编译后就是把一个函数分成多个case 采用指针的方式向下移动(调用next)
3)async/await是什么?async/await相比于Promise的优势?
async函数,就是 Generator 函数的语法糖,内部是通过Promise异步迭代来实现的。
5.闭包
1) 什么是闭包?
函数嵌套函数,内部函数引用了外部函数的变量就形成了闭包了
2) 闭包的作用?
1.延长外部函数变量对象的生命周期
2.让函数外部可以操作(读写)函数内部的数据(变量/函数)
3) 闭包的缺点
延长外部函数变量对象的生命周期(不及时清除容易造成内存溢出、泄漏)
4) 内存泄漏与溢出
泄漏:没用的内存没用被释放掉
溢出:被申请的内存过多
5)开发中应用:
高阶函数(执行函数返回值是另外一个函数)
源码 --> vue双向数据绑定原理 -> 保存this/vm实例对象
6.其它
1)js数据类型有哪些?
JS中的原始数据类型:string,number,undefined,null,boolean,object,Symbol,bigInt
JS中的简单(基本)数据类型:string,number,boolean,undefined,null
JS中的复杂类型:Object,Array,Function,RegExp,Date
jS中的基本包装类型:string,number,boolean (本身可以是基本类型,关键时刻可以当对象使用)
2)如何判断类型?
typeof:不精准检测,null/Array等都是object
instanceof:用来判断对象是不在某个构造函数的原型链上,返回的是true和false,不能精准检测数据类型
Object.prototype.toString.call(target).slice(8, -1):精准检测
3)为什么 0.1 + 0.2 != 0.3(0.2+0.2是准的)
因为计算机采用的是二进制算法,会导致小数精度不准
4)var、let 及 const 区别?
1)var关键字
1.声明的变量会发生预提升
2.不存在块级作用域,能重复声明
2)let关键字
1. 不会预处理,不存在声明提升
2. 存在块作用域,不能重复声明
3)const关键字
1. 不会预处理,不存在声明提升
2. 存在块作用域,不能重复声明
3. 定义一个常量,该常量不能修改
5)Set和Map
1)讲讲Set和Map?
Set容器:无序不可重复的多个值的集合体
Map容器:无序不重复的多个key-value的集合体
6)节流防抖?
节流(抢票):是优化高频率执行js代码的一种手段, 节流可以让逻辑代码在一定时间内只执行一次
防抖(搜索框提示栏):短时间内触发的事件,按最后一次算
7)图片的懒加载和预加载
懒加载:懒加载是先加载一部分资源给用户,等用户需要更多资源时再向服务器请求,可以减少向服务器的请求次数
通过getBoundingRect获取img元素的位置,当图片进入视口时在去给img标签设置src属性
预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。
8)两个独立html页面怎么通信?
如:淘宝A,B页面,A为商品页,B为购物车页,两个页面同时打开,在A页面点击商品添加至购物车,切换到B页面购物车怎么显示该商品信息
解决办法:
1)利用localStroage,A页面将数据存入localStroage,B页面读取localStorage中的数据
2)关键点: B页面如何知道A页面什么时候存数据到localStorage
3)localStorage中有个‘storage’事件
4)window.addEventListener(‘storage’, callback),A页面存数据,B页面监听事件
9)ES6里的symble
它的功能类似于一种标识唯一性的ID,每个Symbol实例都是唯一的。
Symbol类型的key是不能通过Object.keys()或者for...in来枚举的,
它未被包含在对象自身的属性名集合(property names)之中。
所以,利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。
// 使用Object的API Object.getOwnPropertySymbols(obj)获取 // [Symbol(name)]设置
10)普通函数和箭头函数的区别
1.箭头函数是匿名函数,不能作为构造函数,不能使用new
2.箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如call() , bind() , apply()
普通函数的this指向调用它的那个对象
3.箭头函数没有原型属性,不能实现继承
12)new 操作符做了哪些事情?
1. 申请一块空闲的空间,
2. 设置this为当前的实例对象
3. 初始化属性和方法的值
4. 将构造函数的prototype关联到实例的__proto__
14)null,undefined 的区别?
null存在变量值为空,undefined变量都不存在
15)Javascript创建对象的几种方式?
1、对象字面量的方式
var = {}
2、通过构造函数方式创建。
var obj = new Object();
3、通过Object.create()方式创建。
var obj = Object.create(Object.prototype);
16)Ajax原理
Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎),通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。
17)[JavaScript]为什么会阻塞渲染?css会不会阻塞渲染
js是可以操作DOM的,如果在修改元素属性的同时渲染界面,会出现不可预期的结果,导致渲染混乱,因此浏览器设置了GUI渲染现成和js线程互斥,在js执行的时候,GUI线程会被挂起,等空闲的时候再执行。
dom解析和css解析是两个并行的线程,所以css加载不会阻塞dom的解析
但是render tree是依赖dom tree和cssom tree的,因此,css的加载会阻塞dom的渲染
19)异步加载JS 的方法
defer: 该属性能够将JS延迟到页面解析完成才能去执行
async:让浏览器同时加载JS/html文件,但是js加载完就会立马执行,执行的时候就会停止其他操作
20)eval 是做什么的
它的功能是将对应的字符串解析成JS 并执行
21)如何理解前端模块化
前端模块化就是复杂的功能变成一个一个独立的模块,有利于功能重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,
所以有了commonJS 规范,es6规范等等,以及用于JS 打包(编译等处理)的工具webpack
22)CommonJS和es6模块的区别
1.CommonJS:modules.exports/exports导出模块,模块加载require()引入模块,
exports 和 module.exports的区别:
module.exports和exports是引用关系,module.exports={}/exports=module.exports
- 通过exports只能使用.的方式来向外暴露内部变量
- 而module.exports既可以通过.的形式,也可以直接赋值
2.es6:export/export default导出模块,模块加载import from引入模块,
4.CommonJS 模块输出的是一个值的拷贝,被引入模块的值不会被改变,而ES6 模块输出的是值的引用,被引入模块的值会被改变
5.CommonJS 模块是运行时加载模块内容,而ES6模块在编译时就能知道模块是否使用,使得对JS的模块进行tree shaking成为可能;
23)能来讲讲JS 的语言特性吗
1.运行在客户端浏览器上的语言;与操作系统无关,所以可以用它来写跨平台应用。
2.是弱类型语言,较为灵活;
24)简单介绍一下 V8 引擎的垃圾回收机制
内存里的垃圾回收分为新生代(32m,存放临时变量)和老生代(1.4G,放一些长时间使用的变量)垃圾回收机制
新生代垃圾回收
新生代垃圾回收分为from和to两块区域,from里面放代码块,to里面为空,引擎会轮询from里面的变量,会把正在使用的变量
移到to来,然后清空from区域,接着from变成to区域,to变成from区域开始循环上面步骤。轮询多次后依然存活的变量会变移到
老生代区域。或者当to区域内存占用超过25%,那么变量会变移到老生代区域。
老生代垃圾回收
1)标记清除
标记活的变量,标记完后清除死的变量,问题是清除后会出现内存不连续的情况,后面如果要放一个大的对象无法放到内存碎片空间中。
2)标记整理
标记活的变量,然后把活的对象一起往左移到,死的对象往右移动,接着清除死的变量,不会造成内存碎片,但是操作时间久。
3)增量标记
由于在进行垃圾回收的时候会暂停应用的逻辑,停顿会影响用户体验。 为了解决这个问题 V8 引入了增量标记的方法,将一次回收过程分为了多步,每次执行完一小步就让运行逻辑执行一会,就这样交替运行。
4)总结:V8主要使用标记清除,等内存不够了在使用标记整理
25)一个数组如果让你找到最大数,你会怎么弄?
减少空间的话可以用冒泡排序找;减少时间的话可以用二分法。
26)window.onload/DOMContentLoaded/img.onload
window.onload:dom0当所有的节点和资源都加载完毕后才执行
DOMContentLoaded:dom2当所有的节点和资源都加载完毕后才执行
img.onload:图片加载完毕后才执行
27)JSON.parse(JSON.stringify(obj))有什么不足之处?
1.对象中有些特殊属性拷贝不准:
如果对象中有时间对象,那么用该方法拷贝之后的对象中,时间是字符串形式而不是时间对象
如果对象中有RegExp、Error对象,那么序列化的结果是空等
2.如果对象中存在循环引用也无法正确实现深拷贝,会报错
var a={};
a.b=a;
28)clientWidth/offsetWidth/scrollWidth
1)offsetWidth和offsetHeight:获取元素的宽高(content+padding+border)
2)clientWidth和clientHeight:获取元素的宽高(content+padding)
3)scrollWidth和scrollHeight:获取元素的可以滚动的宽度(包含的内容的完全的宽度 + 自身的padding)

面试题
1.作用域和执行上下文?!
2.原型链
1)原型和原型链
2)js中继承方式有哪几种
3)ES5的继承和ES6的继承有什么区别?!
4)浅拷贝和深拷贝的区别?
5)this指向?
3.事件循环机制
1)浏览器的事件环
2)宏任务与微任务
2)node事件环
3)node事件环和浏览器事件环的区别
4)dom事件机制
4.ES6/ES8/ES9
1)你用过哪些 ES6最新的语法?
2)promise对象知识点
1)怎么创建promise对象?
2)Promise解决的哪些问题
3)Promise缺陷
依旧是基于回调函数,可读性必async和await差
4)原理
3)generator函数(迭代器函数)!
4)async/await是什么?async/await相比于Promise的优势?
5.闭包
1) 什么是闭包?
2) 闭包的作用?
3) 闭包的缺点
4) 内存泄漏与溢出
5)开发中应用
6.其它
1)js数据类型有哪些?
2)如何判断类型?
3)为什么 0.1 + 0.2 != 0.3
4)var、let 及 const 区别?
5)Set和Map
6)节流防抖?
7)图片的懒加载和预加载
8)两个独立html页面怎么通信?
9)ES6里的symble
10)普通函数和箭头函数的区别
12)new 操作符做了哪些事情?
14)null,undefined 的区别?
15)Javascript创建对象的几种方式?
16)Ajax原理!
17)[JavaScript]为什么会阻塞渲染?css会不会阻塞渲染
19)异步加载JS 的方法!
21)如何理解前端模块化
22)CommonJS和es6模块的区别!
23)能来讲讲JS 的语言特性吗!
24)简单介绍一下 V8 引擎的垃圾回收机制
25)一个数组如果让你找到最大数,你会怎么弄?
26)window.onload/DOMContentLoaded/img.onload
27)JSON.parse(JSON.stringify(obj))有什么不足之处?
28)clientWidth/offsetWidth/scrollWidth


 

 

 

 


 

 




posted @   流星星星星星  阅读(295)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示