【Web前端面试】葵花宝典(2022版本)——JS篇(上)


## 🍗前言:

本篇文章主要写的是**前端高频面试题JavaScript篇(上)**,如果有需要`http/html/浏览器`方面面试题的小伙伴们,请在下方评论区留言,下下一篇我会更新相关面试题。如果没有的话,下一篇预备更新 **前端高频面试题JavaScript篇(下)**

> + [【Web前端面试】葵花宝典(2022版本)—— CSS篇](http://t.csdn.cn/3fm8J)
> + [【Web前端面试】葵花宝典 (2022版本)—— Vue 篇](http://t.csdn.cn/IBvjL)
> + [【Web前端面试】葵花宝典(2022版本)—— JS篇(下)](http://t.csdn.cn/oDF5t)
> + [【JavaScript】中this指向相关的经典面试题](http://t.csdn.cn/OoqMV)
> + [【JavaScript】作用域提升面试题(详解)](http://t.csdn.cn/nsaR0)

## 🍖正文:

### 1. get 请求传参长度的误区

**误区**:我们经常说 get 请求参数的大小存在限制,而 post 请求的参数大小是无限制的。 实际上 HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对 get 请求参数的限制 是来源与浏览器或 web 服务器,浏览器或 web 服务器限制了 url 的长度。

为了明确这个概念,我们必须再次强调下面几点:

+ HTTP 协议未规定 GET 和 POST 的长度限制 
+ GET 的最大长度显示是因为 浏 览器和 web 服务器限制了 URI 的长度 
+ 不同的浏览器和 WEB 服务器,限制的最大长度不一样 
+ 要支持 IE,则最大长度为 2083byte,若只支持 Chrome,则最大长度 8182byte

### 2.补充 get 和 post 请求在缓存方面的区别

+ get 请求类似于查找的过程,用户获取数据,可以不用每次都与数据库连接,所以可以使用缓存。 
+ post 不同,post 做的一般是修改和删除的工作,所以必须与数据库交互,所以不能使用缓存。因此 get 请求适合于请求缓存。

### 3.说一下闭包

闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用, 子函数所在的父函数的作用域不会被释放。

### 4. 如何解决异步回调地狱

`promise`、`generator`、`async/await`

### 5.什么是事件流

事件流描述的是从页面中接收事件的顺序,DOM2 级事件流包括下面几 阶段。 

+ 事件捕获阶段 

+ 处于目标阶段 

+ 事件冒泡阶

### 6.说说前端中的事件流

HTML 中与 javascript 交互是通过事件驱动来实现的,例如鼠标点击事件 onclick、页面 的滚动事件 onscroll 等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。 想要知道这些事件是在什么时候进行调用的,

### 7.如何让事件先冒泡后捕获

在 DOM 标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓 执行,直到冒泡事件被捕获后再执行捕获之间。

### 8.说一下事件委托

事件委托指的是,不在事件的发生地(直接 `dom`)上设置监听函数,而是在其父 元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判 断事件发生元素 DOM 的类型,来做出不同的响应

举例:最经典的就是 `ul `和 `li `标签的事件监听,比如我们在添加事件时候,采用事件委 托机制,不会在 li 标签上直接添加,而是在 ul 父元素上添加。 好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发 机制。

### 9.说一下图片的懒加载和预加载

预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。 

懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。

两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。 懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

### 10.`mouseover `和 `mouseenter`的区别

+ `mouseover`:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是 `mouseout`
+  `mouseenter`:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是 `mouseleave`

### 11. JS 的 new 操作符做了哪些事情

new 操作符新建了一个空对象,这个对象原型指向构造函数的 prototype,执行构造函数后返回这个对象。

### 12.改变函数内部 this 指针的指向函数(bind,apply,call 的区别)

通过 `apply `和 `call `改变函数的 this 指向,他们两个函数的第一个参数都是一样的表示要 改变指向的那个对象,第二个参数,apply 是数组,而 call 则是 arg1,arg2...这种形式。

通 过 `bind `改变 `this `作用域会返回一个新的函数,这个函数不会马上执行。

详解可以参考这篇文章http://t.csdn.cn/GNtKH

### 13. JS 的各种位置,比如 `clientHeight`,`scrollHeight`,`offsetHeight `,以及 `scrollTop`, `offsetTop`,`clientTop `的区别?

+ `clientHeight`:表示的是可视区域的高度,不包含 border 和滚动条
+ `offsetHeight`:表示可视区域的高度,包含了 border 和滚动条 
+ `scrollHeight`:表示了所有区域的高度,包含了因为滚动被隐藏的部分。 
+ `clientTop`:表示边框 border 的厚度,在未指定的情况下一般为 0 
+ `scrollTop`:滚动后被隐藏的高度,获取对象相对于由 `offsetParent `属性指定的父坐标(css 定位的元素或 body 元素)距离顶端的高度

### 14. JS 拖拽功能的实

首先是三个事件,分别是 mousedown,mousemove,mouseup 当鼠标点击按下的时候,需要一个 tag 标识此时已经按下,可以执行 mousemove 里面的 具体方法。

 clientX,clientY 标识的是鼠标的坐标,分别标识横坐标和纵坐标,并且我们用 offsetX 和 offsetY 来表示元素的元素的初始坐标,移动的举例应该是:

 鼠标移动时候的坐标-鼠标按下去时候的坐标。

 也就是说定位信息为: 鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的 offetLeft。

还有一点也是原理性的东西,也就是拖拽的同时是绝对定位,我们改变的是绝对定位条 件下的 left 以及 top 等等值。

>  补充:也可以通过 html5 的拖放(Drag 和 drop)来实现

### 15.异步加载 JS 的方法

defer:只支持 IE 如果您的脚本不会改变文档的内容,可将 defer 属性加入到`<script>`标 签中,以便加快处理文档的速度。

因为浏览器知道它将能够安全地读取文档的剩余部分而不用执行脚本,它将推迟对脚本的解释,直到文档已经显示给用户为止。 

async,HTML5 属性仅适用于外部脚本,并且如果在 IE 中,同时存在 defer 和 async,那 么 defer 的优先级比较高,脚本将在页面完成时执行。创建 script 标签,插入到 DOM 中

### 16. Ajax 解决浏览器缓存问题

+ 在 ajax 发送请求前加上 `anyAjaxObj.setRequestHeader("If-Modified-Since","0")`。
+  在 ajax 发送请求前加上 `anyAjaxObj.setRequestHeader("Cache-Control","no-cache")`。 
+ 在 URL 后面加上一个随机数:` "fresh=" + Math.random()`。 
+ 在 URL 后面加上时间搓:`"nowtime=" + new Date().getTime()`。 
+ 如果是使用 jQuery,直接这样就可以了: `$.ajaxSetup({cache:false})`。这样页面的所有 ajax 都会执行这条语句就是不需要保存缓存记录。

### 17. JS 中的垃圾回收机制

js的垃圾回收机制就是定时回收闲置资源的一种机制 , 每隔一段时间, 执行环境都会清理内存中一些没用的变量释放它所占用的内存 。

**核心思想 :** 找到没用的变量, 释放它们的内存

### 18. eval 函数是做什么的?

它的功能是将对应的字符串解析成 JS 并执行,应该避免使用 JS,因为非常消耗性能(2 次,一次解析成 JS,一次执行)

**详细案例可以参考这篇文章:**http://t.csdn.cn/rvbx9

### 19.如何理解前端模块化

前端模块化就是复杂的文件编程一个一个独立的模块,比如 JS 文件等等,分成独立的 模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题, 所以有了 **`commonJS`** 规范,AMD,CMD 规范等等,以及用于 JS 打包(编译等处理)的 工具 webpack

### 20.说一下 CommonJS、AMD 

+ CommonJS:开始于服务器端的模块化,同步定义的模块化,每个模块都是一个单独的 作用域,模块输出,modules.exports,模块加载 require()引入模块。

+  AMD:中文名异步模块定义的意思。

  +  requireJS 实现了 AMD 规范,主要用于解决下述两个问题。 1.多个文件有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器 2.加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应的时间越长。 语法:requireJS 定义了一个函数 define,它是全局变量,用来定义模块。

    >  总结 AMD 规范:require()函数在加载依赖函数的时候是异步加载的,这样浏览器不 会失去响应,它指定的回调函数,只有前面的模块加载成功,才会去执行。 因为网页在加载 JS 的时候会停止渲染,因此我们可以通过异步的方式去加载 JS,而如果 需要依赖某些,也是异步去依赖,依赖后再执行某些方法。



### 21. 对象深度克隆的简单实现

```js
function deepClone (obj) {
    var newObj = obj instanceof Array ? [] : {};
    for (var item in obj) {
        var temple = typeof obj[item] == 'object' ? deepClone(obj[item]) : obj[item];
        newObj[item] = temple;
    }
    return newObj;
}
```

ES5 的常用的对象克隆的一种方式。注意数组是对象,但是跟对象又有一定区别,所以 我们一开始判断了一些类型,决定 newObj 是对象还是数组。

### 22.实现一个 once 函数,传入函数参数只执行一次

```js
function ones (func) {
    var tag = true;
    return function () {
        if (tag == true) {
            func.apply(null, arguments);
            tag = false;
        }
        return undefined
    }
}
```



### 23. JS 监听对象属性的改变

**场景假设:我们假设这里有一个 user 对象**

#### (1).在 ES5 中可以通过 Object.defineProperty 来实现已有属性的监听

```js
Object.defineProperty(user, 'name', {
    set:function (key, value) {
    }
})
```

> 缺点:如果 `id`不在`user`对象中,则不能监听id的变化

#### (2)在 ES6 中可以通过 Proxy 来实现

```js
var user = new Proxy({},{
    set:function (target, key, value, receiver) {
    }
})
```

> 这样即使有属性在 `user `中不存在,通过 `user.id` 来定义也同样可以这样监听这个属性的 变化哦

### 24.如何实现一个私有变量,用 getName 方法可以访问,不能直接访问

#### (1)通过 defineProperty 来实现:

```js
obj = {
    name: yuxiaoliang, getName: function () {
        return this.name
    }
}

object.defineProperty(obj, "name", {
    //不可枚举不可配置
});
```

> `通过defineProperty新增的属性,该新属性是不可修改、不可删除以及不可枚举的`

#### (2)通过函数的创建形式

```js
function product () {
    var name = 'why';
    this.getName = function () {
        return name;
    }
}
var obj = new product();
```

### 25. `Function.__proto__(getPrototypeOf)`是什么

获取一个对象的原型,在 chrome 中可以通过_proto_的形式,或者在 ES6 中可以通过 Object.getPrototypeOf 的形式。 那么 Function.proto 是什么么?也就是说 Function 由什么对象继承而来,我们来做如下判别。

```js
 Function.__proto__==Object.prototype //false
Function.__proto__==Function.prototype//true
```

**我们发现 Function 的原型也是Function**

![image-20220610142907611](https://img-blog.csdnimg.cn/17b9d26e3e5545258fca314ec311b54e.png)



### 26. this指向面试题举例

[JavaScript中this指向相关的经典面试题](http://t.csdn.cn/fQpNJ)



### 27. JS 判断类型方法有哪些

+ `typeof()`
+ `instanceof`
+ `Object.prototype.toString.call()`等

### 28.数组常用方法

`push()`,`pop()`,`shift()`,`unshift()`,`splice()`,`sort()``,reverse()`,`map()`

**示例代码**可以查看该链接文章: [【JavaScript】高级语法——常用的数组处理方法](http://t.csdn.cn/UpRNC)

### 29.数组去重

+ 方法一:indexOf 循环去重 
+ 方法二:ES6 Set 去重 `Array.from(new Set(array)) `
+ 方法三:Object 键值对去重;把数组的值存成 Object 的 key 值,比如 `Object[value1] = true`, 在判断另一个值的时候,如果 `Object[value2]`存在的话,就说明该值是重复的。

### 30.闭包有什么用

有关闭包的详细讲解参考下文:

[(详解)JavaScript中的闭包是什么?JavaScript中闭包造成的内存泄漏又怎么解决?](http://t.csdn.cn/095DZ)

### 31.事件代理在捕获阶段的实际应用

可以在父元素层面阻止事件向子元素传播,也可代替子元素执行某些操作。

### 32.去除字符串首尾空格的方法

> `使用正则(^\s*)|(\s*$)即可`

### 33.性能优化都有什么方法

+ 减少 HTTP 请求 
+ 使用内容发布网络(CDN) 
+ 添加本地缓存
+  压缩资源文件 
+ 将 CSS 样式表放在顶部,把 javascript 放在底部(浏览器的运行机制决定) 
+ 避免使用 CSS 表达式 
+ 减少 DNS 查询 
+ 使用外部 javascript 和 CSS 
+ 避免重定向 
+ 图片 `lazyLoad`

### 34.能来讲讲 JS 的语言特性吗

+ 运行在客户端浏览器上; 
+ 不用预编译,直接解析执行代码; 
+ 是弱类型语言,较为灵活; 
+ 与操作系统无关,跨平台的语言; 
+   脚本语言、解释性语言

>✨$\textcolor{blue}{原创不易,还希望各位大佬支持一下}$ <br/>
>👍 $\textcolor{green}{点赞,你的认可是我创作的动力!}$ <br/>
>⭐️ $\textcolor{green}{收藏,你的青睐是我努力的方向!}$ <br/>
>✏️ $\textcolor{green}{评论,你的意见是我进步的财富!}$ <br/>







#邮储面试#
全部评论
感谢大神分享!
点赞
送花
回复
分享
发布于 2022-08-29 11:04 江苏

相关推荐

点赞 评论 收藏
转发
24 176 评论
分享
牛客网
牛客企业服务