前端面试知识点(js)01
1. typeof 与 instanceof 区别
typeof会返回一个变量的基本类型,
instanceof
返回的是一个布尔值instanceof` 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
2. let var const 区别
1.var 声明的变量是存在变量提升的,let ,const声明的变量不存在变量提升。
变量提升:变量提升是指代码在未定义之前可以使用且不会报错
2.在同一作用域下var可以重复声明,let,const不可以重复声明。
3.var声明的变量不存在块级作用域, let,const声明的变量存在块级作用域。
4.var和let可以重新赋值 ,const声明的是一个常量,const声明的变量必须要进行初始化 不能够重新赋值 。
5.var声明的变量不存在暂时性死区,let,const声明的变量存在暂时性死区。
暂时性死区:在变量声明之前,任何的地方都不能去提前使用,一旦使用就会报错,那么这之前的这些代码,对于这个变量来说就是暂时性死区
3. 对作用域的理解
作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合。换句话说,作用域决定了代码区块中变量和其他资源的可见性
比如:
1 | function myFunction() { |
上述例子中,函数 myFunction 内部创建一个 a 变量,当我们在全局访问这个变量的时候,系统会报错。说明我们在全局是无法获取到(闭包除外)函数内部的变量
从变量查找的范围的角度,js 的作用域可以分为3类:全局作用域、函数作用域和块级作用域。
3.1 全局作用域
任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问
1 | var a = 'Hello World!'; |
3.2 局部作用域
局部作用域也叫函数作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问
1 | function my() { |
3.3 块级作用域
ES6引入了let
和const
关键字,和var
关键字不同,在大括号中使用let
和const
声明的变量存在于块级作用域中。在大括号之外不能访问这些变量
1 | { |
3.4 词法作用域
词法作用域,又叫静态作用域,变量被创建时就确定好了,而非执行阶段确定的。也就是说我们写好代码时它的作用域就确定了,JavaScript 遵循的就是词法作用域
1 | var a = 2; |
因为 JavaScript 遵循词法作用域,相同层级的 foo 和 bar 就没有办法访问到彼此块作用域中的变量,所以输出2
3.5 作用域链
当在 JavaScript 中使用一个变量的时候,首先Javascript
引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域。
如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错
1 | var sex = '男'; |
上述代码主要主要做了以下工作:
1.student函数内部属于最内层作用域,找不到name,向上一层作用域 person 函数内部找,找到了输出“张三”
2.student内部输出cat时找不到,向上一层作用域 person 函数找,还找不到继续向上一层找,即全局作用域,找到了输出“男”
3.在person函数内部输出age时找不到,向上一层作用域找,即全局作用域,还是找不到则报错
4. 原型和原型链
原型:函数有原型,函数上有个属性叫 prototype ,函数的这个原型指向一个对象 ,也就是原型对象 ,这个原型对象有一个 constructor 属性 指向函数本身
1 | function a(){} |
控制台的输出:
1 | { |
原型链:每一个实例对象上都有一个proto属性,指向构造函数的原型对象,构造函数的原型对象也是一个对象;也有一个proto属性,这样一层一层往上找到过程就形成原型链

当我们访问对象中的属性时候,会先访问该对象中的本身的属性(私有属性),如果访问不到,会查找对象的“proto”指向的构造函数的prototype对象,如果其中有要访问的属性,就使用该值,否则继续访问prototype的“proto”,在其中查找要访问属性。这样一直上溯到Object对象。这个就是“原型链”。
5. 防抖与节流
本质上是优化高频率执行代码的一种手段
如:浏览器的 resize
、scroll
、keypress
、mousemove
等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能
为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用throttle
(防抖)和debounce
(节流)的方式来减少调用频率
5.1 防抖与节流的定义
节流:当持续触发事件时,保证在一定时间内只调用一次事件处理函数,意思就是说,假设一个用户一直触发这个函数,且每次触发小于既定值,函数节流会每隔这个时间调用一次
防抖:当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定时间到来之前,又触发了事件,就重新开始延时。也就是说当一个用户一直触发这个函数,且每次触发函数的间隔小于既定时间,那么防抖的情况下只会执行一次。
用一句话总结防抖和节流的区别:防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行
5.2 节流
场景:点击按钮重复发送请求:
项目中点击创建、编辑、删除等按钮都会发送http请求,网络卡顿的情况下点击按钮之后不能快速的响应,一般情况下用户会重复点击按钮,所以会造成重复发送请求问题,一定量造成卡顿延迟问题,这个时候便可以采用节流
1 | var throttle = function(func, delay) { |
5.3 防抖
场景:input事件模糊查询
input输入框的input事件会在输入框内容发生改变的时候执行,那么就存在一个问题:每次输入,都会触发input事件,执行函数,或者接口请求,而这并不是我们想要的:比如,你想要模糊查询 “liu” 相关的所有数据,而当你在input框中输入 “l” 的时候就已经触发了input事件,去请求了接口,而这并不是我们想要的。所以,我们的防抖函数就登场了;
1 | function debounce(fn, wait) { |
6. JS 数组去重
Set去重:
1 | var arr = [1,2,2,4,3,4,1,3,2,7,5,6,1] |
indexOf去重:
1 | // 数组去重 |
7. this指向问题
1.全局作用域或者普通函数中 this 指向全局对象 window。
1 | //直接打印 |
2. 方法调用中谁调用 this 指向谁
1 | //对象方法调用 |
3. 在构造函数或者构造函数原型对象中 this 指向构造函数的实例
1 | //不使用new指向window |
4. 箭头函数中指向外层作用域的 this
1 | var obj = { |
8.箭头函数和普通函数有什么区别
区别:
箭头函数在一些情况下书写更简洁(如只有一个参数、函数体直接返回值时候)。
箭头函数没有自己的this,箭头函数内的this变量指向外层非箭头函数的函数的this,或者将该箭头函数作为属性的对象。箭头函数也不支持call()和apply()函数特性。
箭头函数内部不可以使用arguments对象。
箭头函数不可以当做构造函数。