前端最新JavaScript 高级进阶面试题(30题&附答案)

Achong_0427 2024-06-26 13:33:04 阅读 90

目录

1. 说说ECMAScript6 怎么写 class?

2.说说什么是面向对象编程及面向过程编程,它们的异同和优缺点?

3.说说异步编程的实现方式?

4. 说说面向对象编程思想?

5. 说说Gulp 是什么?

6.想实现一个对页面某个节点的拖曳?如何做?

7.封装一个函数,参数是定时器的时间,then 执行回调函数 执行回调函数?

8. 怎么判断两个对象相等? 

9. Javascript全局函数和全局变量? 

10. 项目性能优化有哪些?

11. 说出你对 Electron 的理解?

12. WebSocket 的理解?

13. 什么是单线程,和异步的关系?

14. 说说负载均衡 ?

15. webpack 的一些 plugin ,怎么使用 webpack 对项目进行优化 ?

16. 编写一个 loader?

17. webpack 打包体积优化思路 

18. webpack 打包效率 ?

19. 原型 / 构造函数 / 实例 ?

20. 原型链? 

21. 作用域链?

22. 对象的拷贝? 

23. new 运算符的执行过程?

24. instanceof 原理?

25. 类型判断? 

26. 模块化?

27. 防抖与节流?

28. 函数执行改变 this? 

29. ES6/ES7? 

29. 说说你对 promise 的了解?

30. 谈谈你对 AMD 、CMD 的理解?


1. 说说ECMAScript6 怎么写 class?

这个语法糖可以让有 OOP 基础的人更快上手 js ,至少是一个官方的实现了。对熟悉 js 的人来说,这个东西没啥大影响;一个 Object.creat() 搞定继承,比 class 简洁清晰的多。

2.说说什么是面向对象编程及面向过程编程,它们的异同和优缺点?

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。面向对象是以功能来划分问题,而不是步骤。

3.说说异步编程的实现方式?

回调函数:优点:简单、容易理解缺点:不利于维护,代码耦合高事件监听(采用时间驱动模式,取决于某个事件是否发生):优点:容易理解,可以绑定多个事件,每个事件可以指定多个回调函数缺点:事件驱动型,流程不够清晰发布/订阅(观察者模式)类似于事件监听,但是可以通过‘消息中心’,了解现在有多少发布者,多少订阅者Promise 对象:优点:可以利用 then 方法,进行链式写法;可以书写错误时的回调函数缺点:编写和理解,相对比较难Generator 函数:优点:函数体内外的数据交换、错误处理机制缺点:流程管理不方便async 函数:优点:内置执行器、更好的语义、更广的适用性、返回的是 Promise、结构清晰缺点:错误处理机制

4. 说说面向对象编程思想?

基本思想是使用对象,类,继承,封装等基本概念来进行程序设计优点:易维护易扩展开发工作的重用性、继承性高,降低重复工作量。缩短了开发周期

5. 说说Gulp 是什么?

gulp 是前端开发过程中一种基于流的代码构建工具,是自动化项目的构建利器;它不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成Gulp 的核心概念:流流:就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向gulp 正是通过流和代码优于配置的策略来尽量简化任务编写的工作

6.想实现一个对页面某个节点的拖曳?如何做?

给需要拖拽的节点绑定 mousedown , mousemove , mouseup 事件mousedown 事件触发后,开始拖拽mousemove 时,需要通过 event.clientX 和 clientY 获取拖拽位置,并实时更新位置mouseup 时,拖拽结束需要注意浏览器边界的情况

7.封装一个函数,参数是定时器的时间,then 执行回调函数 执行回调函数?

function sleep(time) {

return new Promise((resolve) => setTimeout(resolve, time));

}

8. 怎么判断两个对象相等? 

obj = { a: 1, b: 2 }

obj2 = { a: 1, b: 2 }

obj3 = { a: 1, b: '2' }

JSON.stringify(obj) == JSON.stringify(obj2);//true

JSON.stringify(obj) == JSON.stringify(obj3);//false

9. Javascript全局函数和全局变量? 

全局变量:Infinity 变量代表正的无穷大的数值NaN 指示某个值是不是数字值undefined 指示未定义的值全局函数:decodeURI() 解码某个编码的 URI 。decodeURIComponent() 解码一个编码的 URI 组件。encodeURI() 把字符串编码为 URI。encodeURIComponent() 把字符串编码为 URI 组件。escape() 对字符串进行编码。eval() 计算 JavaScript 字符串,并把它作为脚本代码来执行。isFinite() 检查某个值是否为有穷大的数。isNaN() 检查某个值是否是数字。Number() 把对象的值转换为数字。parseFloat() 解析一个字符串并返回一个浮点数。parseInt() 解析一个字符串并返回一个整数。 String() 把对象的值转换为字符串。unescape() 对由 escape() 编码的字符串进行解码

10. 项目性能优化有哪些?

减少 HTTP 请求数减少 DNS 查询使用 CDN避免重定向图片懒加载减少 DOM 元素数量减少 DOM 操作使用外部 JavaScript 和 CSS压缩 JavaScript 、 CSS 、字体、图片等优化 CSS Sprite使用 iconfont字体裁剪多域名分发划分内容到不同域名尽量减少 iframe 使用避免图片 src 为空把样式表放在 link 中把 JavaScript 放在页面底部

11. 说出你对 Electron 的理解?

减少 HTTP 请求数最最重要的一点, electron 实际上是一个套了 Chrome 的 nodeJS 序Chrome 无各种兼容性问题NodeJS

12. WebSocket 的理解?

历史来源:序由于 http 存在一个明显的弊端(消息只能有客户端推送到服务器端,而服务器端不能主动推送到客户端),导致如果服务器如果有连续的变化,这时只能使用轮询,而轮询效率过低,并不适合。于是 WebSocket 被发明出来支持双向通信,实时性更强;可以发送文本,也可以二进制文件协议标识符是 ws ,加密后是 wss较少的控制开销。连接创建后, ws 客户端、服务端进行数据交换时,协议控制的数据包头部较小。在不包含头部的情况下,服务端到客户端的包头只有 2~10 字节(取决于数据包长度),客户端到服务端的的话,需要加上额外的 4 字节的掩码。而 HTTP 协议每次通信都需要携带完整的头部;支持扩展。ws 协议定义了扩展,用户可以扩展协议,或者实现自定义的子协议。(比如支持自定义压缩算法等)无跨域问题

13. 什么是单线程,和异步的关系?

单线程 - 只有一个线程,只能做一件事原因 - 避免 DOM 渲染的冲突:

浏览器需要渲染 DOMJS 可以修改 DOM 结构JS 执行的时候,浏览器 DOM 渲染会暂停两段 JS 也不能同时执行(都修改 DOM 就冲突了)webworker 支持多线程,但是不能访问 DOM

解决方案 - 异步

14. 说说负载均衡 ?

单台服务器共同协作,不让其中某一台或几台超额工作,发挥服务器的最大作用http 重定向负载均衡:调度者根据策略选择服务器以 302 响应请求,缺点只有第一次有效果,后续操作维持在该服务器 dns 负载均衡:解析域名时,访问多个 ip 服务器中的一个(可监控性较弱)原因 - 避免 DOM 渲染的冲突反向代理负载均衡:访问统一的服务器,由服务器进行调度访问实际的某个服务器,对统一的服务器要求大,性能受到 服务器群的数量

15. webpack 的一些 plugin ,怎么使用 webpack 对项目进行优化 ?

构建优化:

减少编译体积 ContextReplacementPugin 、 IgnorePlugin 、 babel-plugin-import 、babelplugin-transform-runtime并行编译 happypack 、 thread-loader 、 uglifyjsWebpackPlugin 开启并行缓存 cache-loader 、 hard-source-webpack-plugin 、 uglifyjsWebpackPlugin 开启缓存、babel-loader 开启缓存:预编译 dllWebpackPlugin && DllReferencePlugin 、 auto-dll-webapck-plugin

原因 - 避免 DOM 渲染的冲突:

减少编译体积 Tree-shaking 、 Scope Hositinghash 缓存 webpack-md5-plugin拆包 splitChunksPlugin 、 import() 、 require.ensure

16. 编写一个 loader?

loader 就是一个 node 模块,它输出了一个函数。当某种资源需要用这个loader 转换时,这个函数会被调用。并且,这个函数可以通过提供给它的this 上下文访问 Loader API 。 reverse-txt-loader

module.exports = {

module: {

rules: [

{ test: /\.css$/, use: 'css-loader' },

{ test: /\.ts$/, use: 'ts-loader' }

]

}

};

17. webpack 打包体积优化思路 

提取第三方库或通过引用外部文件的方式引入第三方库代码压缩插件 UglifyJsPlugin服务器启用 gzip 压缩按需加载资源文件 require.ensure优化 devtool 中的 source-map剥离 css 文件,单独打包去除不必要插件,通常就是开发环境与生产环境用同一套配置文件导致

18. webpack 打包效率 ?

开发环境采用增量构建,启用热更新开发环境不做无意义的工作如提取 css 计算文件 hash 等配置 devtool选择合适的 loader个别 loader 开启 cache 如 babel-loader第三方库采用引入方式提取公共代码优化构建时的搜索路径 指明需要构建目录及不需要构建目录模块化引入需要的部分

19. 原型 / 构造函数 / 实例 ?

原型( prototype ): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个 JavaScript 对象中都包含一个 __proto__ (非标准)的属性指向它爹(该对象的原型),可 obj.__proto__ 进行访问。构造函数: 可以通过 new 来 新建一个对象 的函数。实例: 通过构造函数和 new 创建出来的对象,便是实例。 实例通过 __proto__ 指向原型,通过 constructor 指向构造函数。以 Object 为例,我们常用的 Object 便是一个构造函数,因此我们可以通过它构建实例:

// 实例

const instance = new Object()

则此时, 实例为 instance , 构造函数为 Object ,我们知道,构造函数拥有一个 prototype的属性指向原型,因此原型为: 

// 实例

const prototype = Object.prototype

原型 / 构造函数 / 实例三者的关系实例.__proto__ === 原型原型.constructor === 构造函数构造函数.prototype === 原型 

// 这条线其实是是基于原型进行获取的,可以理解成一条基于原型的映射线

// 例如:

// const o = new Object()

// o.constructor === Object --> true

// o.__proto__ = null;

// o.constructor === Object --> false

实例.constructor === 构造函数

20. 原型链? 

原原型链是由原型对象组成,每个对象都有 __proto__ 属性,指向了创建该对象的构造函数的原型, __proto__ 将对象连接起来组成了原型链。是一个用来实现继承和共享属性的有限的对象链。属性查找机制: 当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象 Object.prototype ,如还是没找到,则输出 undefined 。属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用: b.prototype.x = 2 ;但是这样会造成所有继承于该对象的实例的属性发生改变。

21. 作用域链?

原我们知道,我们可以在执行上下文中访问到父级甚至全局的变量,这便是作用域链的功

劳。作用域链可以理解为一组对象列表,包含 父级和自身的变量对象,因此我们便能通过作用

域链访问到父级里声明的变量或者函数。

由两部分组成:

[[scope]] 属性: 指向父级变量对象和作用域链,也就是包含了父级的 [[scope]] 和 AO 。AO : 自身活动对象。如此 [[scopr]] 包含 [[scope]] ,便自上而下形成一条 链式作用域。

22. 对象的拷贝? 

浅拷贝: 以赋值的形式拷贝引用对象,仍指向同一个地址,修改时原对象也会受到影响 以赋值的形式拷贝引用对象,仍指向同一个地址,修改时原对象也会受到影响

Object.assign展开运算符( ... )

深拷贝 深拷贝: 完全拷贝一个新对象,修改时原对象不再受到任何影响 完全拷贝一个新对象,修改时原对象不再受到任何影响

JSON.parse(JSON.stringify(obj)) : 性能最快具有循环引用的对象时,报错当值为函数、 undefined 、或 symbol 时,无法拷贝递归进行逐一赋值

23. new 运算符的执行过程?

新生成一个对象链接到原型: obj.__proto__ = Con.prototype绑定 this: apply返回新对象(如果构造函数有自己 retrun 时,则返回该值)

24. instanceof 原理?

新能在实例的 原型对象链 中找到该构造函数的 prototype 属性所指向的 原型对象,就返回 true 。即:

// __proto__: 代表原型对象链

instance.[__proto__...] === instance.constructor.prototype

// return true

25. 类型判断? 

原我判断 Target 的类型,单单用 typeof 并无法完全满足,这其实并不是 bug ,本质原因是

JS 的万物皆对象的理论。因此要真正完美判断时,我们需要区分对待

基本类型( null ): 使用 String(null) 。基本类型( string/number/boolean/undefined ) + function : - 直接使用 typeof 即可其余引用类型( Array/Date/RegExp Error ): 调用 toString 后根据 [object XXX] 进行判断

26. 模块化?

原模块化开发在现代开发中已是必不可少的一部分,它大大提高了项目的可维护、可拓展和

可协作性。通常,我们 在浏览器中使用 ES6 的模块化支持,在 Node 中使用 commonjs 的模块化

支持

分类:

es6: import / exportcommonjs: require / module.exports / exportsamd: require / defined

require 与 import 的区别:

require 支持 动态导入, import 不支持,正在提案 ( babel 下可支持)require 是 同步 导入, impor t 属于 异步 导入require 是 值拷贝,导出值变化不会影响导入值; import 指向 内存地址,导入值会随导出值而变化

27. 防抖与节流?

防抖与节流函数是一种最常用的 高频触发优化方式,能对性能有较大的帮助。

防抖 ( debounce ): 将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可:

function debounce(fn, wait, immediate) {

let timer = null

return function () {

let args = arguments

let context = this

if (immediate && !timer) {

fn.apply(context, args)

}

if (timer) clearTimeout(timer)

timer = setTimeout(() => {

fn.apply(context, args)

}, wait)

}

}

节流(throttle): 每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景: 滚动条事件 或者 resize 事件,通常每隔 100~500 ms 执行一次即可:

function throttle(fn, wait, immediate) {

let timer = null

return function () {

let args = arguments

let context = this

if (callNow) {

fn.apply(context, args)

callNow = false

}

if (!timer) {

timer = setTimeout(() => {

fn.apply(context, args)

}, wait)

}

}

}

28. 函数执行改变 this? 

由于 JS 的设计原理: 在函数中,可以引用运行环境中的变量。因此就需要一个机制来让我们可以在函数体内部获取当前的运行环境,这便是 this 。obj.fn() ,便是 obj 调用了函数,既函数中的 this === objfn() ,这里可以看成 window.fn() ,因此 this === window三种方式可以手动修改 this 的指向:call: fn.call(target, 1, 2)apply: fn.apply(target, [1, 2])bind: fn.bind(target)(1,2)

29. ES6/ES7? 

声明:

let / const : 块级作用域、不存在变量提升、暂时性死区、不允许重复声明const : 声明常量,无法修改

解构赋值:

calss/extend: 类声明与继承Set/Map: 新的数据结构

异步解决方案:

Promise 的使用与实现generator: 1. yield : 暂停代码 2.next() : 继续执行代码await/async : 是 generator 的语法糖, babel 中是基于 promise 实现。

29. 说说你对 promise 的了解?

依照 Promise/A+ 的定义, Promise 有四种状态:

pending: 初始状态, 非 fulfilled 或 rejected.ulfilled: 成功的操作.rejected: 失败的操作.settled: Promise 已被 fulfilled 或 rejected ,且不是 pending

另外, fulfilled 与 rejected 一起合称 settledPromise 对象用来进行延迟( deferred ) 和异步( asynchronous ) 计算Promise 的构造函数 的构造函数构造一个 Promise ,最基本的用法如下:

var promise = new Promise(function (resolve, reject) {

if (...) { // succeed

resolve(result);

} else { // fails

reject(Error(errMessage))

}

})

Promise 实例拥有 then 方法(具有 then 方法的对象,通常被称为 thenable )。它的使用方法如下: 

promise.then(onFulfilled, onRejected)

接收两个函数作为参数,一个在 fulfilled 的时候被调用,一个在 rejected 的时候被调用,接收参数就是 future , onFulfilled 对应 resolve , onRejected 对应 reject 

30. 谈谈你对 AMD 、CMD 的理解?

CommonJS 是服务器端模块的规范, Node.js 采用了这个规范。 CommonJS 规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。 AMD 规范则是非同步加载模块,允许指定回调函数。AMD 推荐的风格通过返回一个对象做为模块对象, CommonJS 的风格通过对 module.exports或 exports 的属性赋值来达到暴露模块对象的目的。es6 模块 CommonJS 、AMD 、CMDCommonJS 的规范中,每个 JavaScript 文件就是一个独立的模块上下文 modulecontext ),在这个上下文中默认创建的属性都是私有的。也就是说,在一个文件定义的变量(还包括函数和类),都是私有的,对其他文件是不可见的。CommonJS 是同步加载模块,在浏览器中会出现堵塞情况,所以不适用 AMD 异步,需要定义回调 define 方式 es6 一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用 export 关键字输出该变量es6 还可以出类、方法,自动适用严格模式。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。