前端高频JS面试题(附答案+视频讲解)

高频前端js面试题总结 对应的视频讲解位置

2023前端高频面试题-JS高频面试题(上)_哔哩哔哩_bilibili

目录

1. var let const 的区别?

2. javascript 有哪些基础数据类型?

3. null和undefined区别

4. == 与 === 的区别?

5. js中那些数据在 if 判断时是 false

6. 判断数据类型的方法有哪些,有什么区别

7. JS垃圾回收

8. this指向

9. call、apply、bind

10. 闭包、闭包的使用场景

11. 什么是事件代理/事件委托?

12. 如何阻止事件冒泡?

13. new操作符的实现原理

14. 回流与重绘

15. Javascript原型链

16. 深拷贝浅拷贝

17. 数组去重

18. 数组的方法

19. 箭头函数和普通函数的区别

20. forEach和map方法有什么区别

21. for...in和for...of的区别


1. var let const 的区别?

  1. const 定义常量, 不可以重复赋值    块级作用域   不存在变量提升
  1. var 定义变量,可以重复声明  var 全局作用域或函数作用域    有变量提升
  2. let 定义变量,不可以重复声明 , 块级作用域   不存在变量提升

2. javascript 有哪些基础数据类型?

  • 基础数据类型String、Number、Boolean、Undefined、Null
  • 引用数据类型: Object、Array、Function、Date等
  • Symbol、BigInt是ES6之后新增的 属于基本数据类型
    • Symbol

指的是独一无二的值

    • BigInt

是一种数字类型的数据,它可以表示任意精度格式的整数

3. null和undefined区别

  • 首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。
  • undefined 代表的含义是

未定义,一般变量声明了但还没有定义的时候会返回 undefined

  • null 代表的含义是

空对象。null主要用于赋值给一些可能会返回对象的变量,作为初始化。

4. == 与 === 的区别?

  1. 双等号(==)进行相等判断时,如果两边的类型不一致,会强制类型转化再进行比较。
  2. 三等号(===)进行相等判断时,如果两边的类型不一致,不强制类型准换,直接返回 false

Object.is()

[]==[]

5. js中那些数据在 if 判断时是 false

  • 0、“”、false、null、undefined、NaN 判断为false (6个)
  • 其他皆为true

[]==false 和 ![]==false true

第一个 []==false 转为数字 0==0

第二个 ![]==false 转为布尔 false==false

[]==[] -- >false

js中布尔值为false的六种情况

下面6种值转化为布尔值时为false,其他转化都为true

1、undefined(未定义,找不到值时出现)

2、null(代表空值)

3、false(布尔值的false,字符串"false"布尔值为true)

4、0(数字0,字符串"0"布尔值为true)

5、NaN(无法计算结果时出现,表示"非数值";但是typeof NaN===“number”)

6、""(双引号)或’’(单引号) (空字符串,中间有空格时也是true)

注意空数组空对象,负值转的布尔值时都为true

6. 判断数据类型的方法有哪些,有什么区别

判断数据类型的方法

描述

typeof

判断基础数据类型(数组、对象、null都会被判断为object)

instanceof

判断引用数据类型,不能判断基本数据类型

constructor

判断数据的类型

Object.prototype.toString.call()

使用 Object 对象的原型方法 toString 来判断数据类型

 JavaScript类型判断的四种方法

一、typeof

typeof是一个操作符而不是函数,其右侧跟一个一元表达式,并返回这个表达式的数据类型。

返回的结果用该类型的字符串(全小写字母)

用于判断数据类型,返回值为6个[字符串],分别为string、Boolean、number、function、object、undefined。

console.log(typeof undefined) // undefind
console.log(typeof null)   // object
console.log(typeof true)   // boolean
console.log(typeof 43)    // number
console.log(typeof '21')   // string
console.log(typeof {a:1})   // object
console.log(typeof Symbol()) // symbol
console.log(typeof 123n)   // bigint
function a() {}
console.log(typeof a)     // function
var date = new Date()
var error = new Error()
console.log(typeof date)   // object
console.log(typeof error)   // object
​

二、instanceof

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型

instanceof用来判断对象,代码形式为obj1 instanceof obj2(obj1是否是obj2的实例),obj2必须为对象,否则会报错!其返回值为布尔值

通俗一些讲,instanceof 用来比较一个对象是否为某一个构造函数的实例。注意,instanceof可以准确的判断复杂数据类型,但是不能正确判断基本数据类型

console.log(12 instanceof Number) // false
console.log('22' instanceof String) // false
console.log(true instanceof Boolean) // false
console.log(null instanceof Object) // false
console.log(undefined instanceof Object) // false
console.log([] instanceof Array)  // true
console.log({a: 1} instanceof Object) // true
console.log(json instanceof Object) // true
function a() { }
console.log(a instanceof Function) // true
console.log(new Date() instanceof Date) //true
let reg=new RegExp()
console.log(reg instanceof RegExp) //true
let error=new Error()
console.log(error instanceof Error) // true

三、Object.prototype.toString.call()

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

console.log(Object.prototype.toString.call(1))     // [object Number]
console.log(Object.prototype.toString.call(1n))     // [object BigInt]
console.log(Object.prototype.toString.call('123'))   // [object String]
console.log(Object.prototype.toString.call(true))    // [object Boolean]
console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(null))    // [object Null]
console.log(Object.prototype.toString.call({}))     // [object Object]
console.log(Object.prototype.toString.call([]))     // [object Array]
console.log(Object.prototype.toString.call(function a() {})) // [object Function]
console.log(Object.prototype.toString.call(Symbol()))     // [object Symbol]
console.log(Object.prototype.toString.call(Math))       // [object Math]
console.log(Object.prototype.toString.call(JSON))       // [object JSON]
console.log(Object.prototype.toString.call(new Date()))    // [object Date]
console.log(Object.prototype.toString.call(new RegExp()))   // [object RegExp]
console.log(Object.prototype.toString.call(new Error))    // [object Error]
console.log(Object.prototype.toString.call(window)      // [object Window]
console.log(Object.prototype.toString.call(document)     // [object HTMLD

四、constructor

constructor属性,可以得知某个实例对象,到底是哪一个构造函数产生的。 constructor属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。所以,修改原型对象时,一般要同时修改constructor属性的指向。

constructor属性,可以得知某个实例对象,到底是哪一个构造函数产生的。
constructor属性表示原型对象与构造函数之间的关联关系,如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错。所以,修改原型对象时,一般要同时修改constructor属性的指向。
console.log('22'.constructor === String)       // true
console.log(true.constructor === Boolean)      // true
console.log([].constructor === Array)        // true
console.log(document.constructor === HTMLDocument)  // true
console.log(window.constructor === Window)      // true
console.log(new Number(22).constructor === Number)  // true
console.log(new Function().constructor === Function) // true
console.log((new Date()).constructor === Date)    // true
console.log(new RegExp().constructor === RegExp)   // true
console.log(new Error().constructor === Error)    // true

注意:

1、null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

2、函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

7. JS垃圾回收

有两种垃圾回收策略:

  1. 标记清除:

标记阶段即为所有活动对象做上标记,清除阶段则把没有标记(也就是非活动对象)销毁。

  1. 引用计数:

它把对象是否不再需要简化定义为对象:有没有其他对象引用到它。如果没有引用指向该对象(引用计数为 0),对象将被垃圾回收机制回收。

8. this指向

9. call、apply、bind

三者区别

  • 三者都可以改变函数的this对象指向
  • 三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window
  • 三者都可以传参,
    • call是参数列表,apply是数组,call和apply是一次性传入参数,
    • bind是参数列表,但可以分为多次传入参数
  • bind是返回绑定this之后的函数,apply、call 则是立即执行

应用场景

  1. call 经常做继承。
  2. apply 经常跟数组有关系,比如借助于数学对象实现数组最大值最小值。
  3. bind 不调用函数,但是还想改变this指向,比如改变定时器内部的this指向。

10. 闭包、闭包的使用场景

闭包的概念:

闭包:是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

闭包的特性

1.函数内再嵌套函数 2.内部函数可以引用外层的参数和变量 3.参数和变量不会被垃圾回收机制回收

闭包的优缺点

  • 优点:延长变量生命周期、私有化变量
  • 缺点:过多的闭包可能会导致内存泄漏

闭包的应用场景

  • ajax请求的成功回调
  • 事件绑定的回调方法
  • setTimeout的延时回调
  • 函数内部返回另一个匿名函数
  • 函数节流、防抖 封装模块

11. 什么是事件代理/事件委托?

事件代理/事件委托是利用事件冒泡的特性,将本应该绑定在多个元素上的事件绑定在他们的祖先元素上,尤其在动态添加子元素的时候,可以非常方便的提高程序性能,减小内存空间。

12. 如何阻止事件冒泡?

w3c的方法是e.stopPropagation(),

e.stopPropagation();

如何阻止默认事件?

w3c的方法是e.preventDefault()

function stopDefault( e ) { e.preventDefault(); }

13. new操作符的实现原理

  1. 首先创建了一个新的空对象
  2. 设置原型,将对象的原型设置为函数的 prototype 对象。
  3. 让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
  4. 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。

14. 回流与重绘

当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树。完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘

15. Javascript原型链

首先理解三个概念:

  • prototype:原型对象,每个函数都有一个 prototype 属性,再通过 new 命令实例对象时,该属性会成为该实例的原型对象。
  • constructor:构造函数。指向原型对象的 constructor
  • __proto__:实例对象的原型

在javascript中,实例对象与原型之间的链接,叫做原型链。Javascript解析引擎在读取一个Object的属性的值时,会沿着原型链向上寻找,如果最终没有找到,则该属性值为undefined;如果最终找到该属性的值,则返回结果。

16. 深拷贝浅拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

浅拷贝

// 第一层为深拷贝 Object.assign() Array.prototype.slice() //扩展运算符 ...

深拷贝

JSON.parse(JSON.stringify())

递归函数

let obj = {
    a: 'hello',
    b: [10, 20],
    c: { name: 'admin',age:{xx:''} }
}

//定义函数实现深层拷贝
function deepCopy(obj) {
    //1. 先判断obj是否存在 是否是对象格式 
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    //2. 创建一个新的容器存储拷贝的数据 
    let newObj = Array.isArray(obj) ? [] : {};
    //3. 遍历对象for循环可以 获取所有的下标keys 
    let temp=null;// temp键值
    //遍历下标 --获取元素的值
    for(let key in obj){
        temp=obj[key];//键值
        //获取键值 存储新的容器里--需要判断当前的键值的类型是不是对象 
        if(temp && typeof temp ==='object'){
            newObj[key]=deepCopy(temp)
            //newObject={a:hello,b}
        }else{
            //键值是基本数据类型可以直接存储
            newObj[key]=temp;
        }
    }
    return newObj;
}

let obj2=deepCopy(obj)

17. 数组去重

  1. 使用es6 set方法

[...new Set(arr)]

let arr = [1,2,3,4,3,2,3,4,6,7,6]; let unique =(arr)=>[...newSet(arr); unique(arr);//[1,2,3,4,6,7]

  1. 利用新数组indexOf查找indexOf()方法可返回某个指定的元素在数组中首次出现的位置。如果没有就返回-1。
  2. for双重循环通过判断第二层循环,去重的数组中是否含有该元素,如果有就退出第二层循环,如果没有j==result.length就相等,然后把对应的元素添加到最后的数组里面。

18. 数组的方法

数组的方法

描述

map

遍历数组,返回回调返回值组成的新数组

forEach

无法break,可以用try/catch中throw new Error来停止

filter

过滤

some

有一项返回true,则整体为`true

every

有一项返回false,则整体为`false

join

通过指定连接符生成字符串

push / pop

末尾推入和弹出,改变原数组。push 返回数组长度, pop 返回原数组最后一项;

unshift / shift

头部推入和弹出,改变原数组,unshift 返回数组长度,shift 返回原数组第一项 ;

sort(fn) / reverse

排序与反转,改变原数组

concat

连接数组,不影响原数组, 浅拷贝

slice(start, end)

返回截断后的新数组,不改变原数组

splice(start, number, value...)

返回删除元素组成的数组,value 为插入项,改变原数组

indexOf / lastIndexOf(value, fromIndex)

查找数组项,返回对应的下标

reduce / reduceRight(fn(prev, cur), defaultPrev)

两两执行,prev 为上次化简函数的return值,cur 为当前值 当传入 defaultPrev 时,从第一项开始; 当未传入时,则为第二项

19. 箭头函数和普通函数的区别

  1. 箭头函数比普通函数更加简洁
  2. 箭头函数没有自己的this
  3. 箭头函数继承来的this指向永远不会改变
  4. 箭头函数不能作为构造函数使用
  5. 箭头函数没有自己的arguments
  6. 箭头函数没有prototype
  7. call()、apply()、bind()等方法不能改变箭头函数中this的指向

20. forEach和map方法有什么区别

  • forEach()方法会针对每一个元素执行提供的函数,对数据的操作会改变原数组,该方法没有返回值;
  • map()方法不会改变原数组的值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值;

注意:

  •  forEach()会改变原数组的方法
  • 参数:item数组中的当前项,index当前项的索引,array原始数组;
  • 数组中有几项,那么传递进去的匿名回调函数就需要执行几次

使用场景:当我们对数组的元素进行处理时(例如:增加元素,元素值改变),可以使用这个函数

注意:

item数组中的当前项,index当前项的索引,array原始数组

map的回调函数中支持return返回值,return的是啥,相当于把数组中的这一项变为啥(并不影响原来的数组,只是相当于把原数组克隆了一份,把克隆这一份的数组中的对应项改变了 );

map会改变原数组的方法,

map的执行速度更快,比forEach的执行速度快了70%;

使用场景:

map适用于你要改变数据值的时候,不仅在于它更快,而且返回一个新的数组,这样可以提高复用性(map(),filter(),reduce())等组合使用。

var arr = [1, 2, 3, 4, 5]; var newArr = arr.map(num => num * 2).filter(num => num > 5); // newArr = [6, 8, 10]

总结:

  1. 能用forEach()做到的,map()同样可以。反之亦成立
  2. map()会分配内存空间存储新数组并返回,forEach()不会返回数组
  3. forEach()允许callback更改原始数组的元素。而map()返回新的数组

21. for...in和for...of的区别

  • for…of 遍历获取的是对象的键值,for…in 获取的是对象的键名;
  • for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链;
  • 对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值;
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值