前端高频面试题—JavaScript篇(二)
- 开源代码
- 2025-08-20 05:30:02

💻前端高频面试题—JavaScript篇(二) 🏠专栏:前端面试题 👀个人主页:繁星学编程🍁 🧑个人简介:一个不断提高自我的平凡人🚀 🔊分享方向:目前主攻前端,其他知识也会阶段性分享🍀 👊格言:☀️没有走不通的路,只有不敢走的人!☀️ 👉让我们一起进步,一起成为更好的自己!!!🎁
文章目录 前端高频面试题—JavaScript篇(二)一. let const var的区别(1) let/const 和 var的区别1. 预解析2. 重复变量名3. 块级作用域 (2) let 和 const区别1. 变量值可以变2. 初始化赋值 (3) 总结 二. 讲讲this(1) this的指向(2) 如何改变this的指向方法1. call()方法2. apply()方法3. bind()方法 (3).改变this指向的方法有什么区别(4) call apply bind原理理解(5) 箭头函数没有this 三. 讲讲Map和Set?数据结构 Set(1) 创建 Set 数据结构(2) Set 数据结构的属性和方法(3) Set中判断两个值是否不同 数据结构 Map(1) Map 基本概念(2) Map 特征(3) Maps 和 Objects 的区别(4) 创建一个 Map数据结构(5) Map 数据结构的属性和方法 四. new的过程发生了什么五. localStorage sessionStorage cookies 有什么区别(1) 什么是会话级存储(2) 什么是持久性存储(3) 什么是cookie(4) cookie和storage的区别(5) localStorage和sessionStorage的区别 前端高频面试题—JavaScript篇(二)本文主要讲述的前端高频面试题知识有:
let const var的区别讲讲this讲讲Map和Set数据结构new的过程发生了什么localStorage sessionStorage cookies 有什么区别 一. let const var的区别ES6新增了两种定义变量和常量的关键字let和const
目的:解决原有语法上的一些不足
let 定义变量 const 定义常量
(1) let/const 和 var的区别 1. 预解析var 会进行预解析
let/const 没有预解析,必须先声明后使用
// eg: 使用var声明 console.log(username); // undefined // var 会进行预解析 var username = "tom"; console.log(username); // tom fn(); // 1 function fn() { console.log(1); } fn(); // 1 // eg: 使用let声明 console.log(num); let num = 100; console.log(num); // 报错:Uncaught ReferenceError: Cannot access 'num' before initialization 2. 重复变量名var 定义的变量可以重名
let/const 不允许定义重复的变量
// eg:使用var重复声明变量(后面的会覆盖前面的) var num = 100; var num = 200; console.log(num); // 200 // eg:使用let/const重复声明变量报错:(Uncaught SyntaxError: Identifier 'num' has already been declared) let num = 100; let num = 200; const num = 100; const num = 200; 3. 块级作用域var 没有块级作用域,只有函数能限制变量的使用范围
let/const 有块级作用域,任何一个可以执行代码的 {} 都会限制变量的使用范围
if (10 > 1) { let num = 100; console.log(num); // 100 const a = 200; console.log(a); // 200 } console.log(a); // 报错:Uncaught ReferenceError: a is not defined console.log(num); (2) let 和 const区别 1. 变量值可以变let 定义的变量可以修改值
const 对于普遍类型声明之后值不可改变,复杂类型声明后值可以改变,但是类型不可改变(因为赋值复杂数据类型的时候传的不是值,是地址)
let num = 100; num = 200; console.log(num); // 200 const num = 100; num = 200; console.log(num); // 报错:Uncaught TypeError: Assignment to constant variable注:const存的值是引用数据类型的时候,只要地址没变就可以
const obj = { username: "tom", }; obj.username = "jerry"; console.log(obj); // {"username": "jerry"}把const声明的常量的地址改变,就会报错
obj = { age: 18 }; console.log(obj); // 报错:Uncaught TypeError: Assignment to constant variable 2. 初始化赋值let 定义的时候可以不赋值 const 定义的时候必须赋值,而且一旦赋值不允许修改
let num; num = 100; console.log(num); // 100 const num; num = 100; console.log(num); // 报错:Uncaught SyntaxError: Missing initializer in const declaration (3) 总结 区别varletconst变量提升可以不可以不可以预解析可以不可以不可以定义的是变量变量常量重复声明可以不可以不可以块级作用域没有有有修改声明的变量能能不能先声明在赋值可以可以不可以(一旦声明必须初始化)注:const实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动
二. 讲讲this1.this指向调用者这个关系一定要清楚 2.要知道改变this指向的几种方式(call, bind, apply) 3.箭头函数中this的特殊性要能讲清楚 4.call apply bind原理理解
什么是this?
它是一个js内的关键字,是一个使用在作用域内的关键字。
(1) this的指向全局中的this ==> window
函数中的this:
不管函数怎么定义,不管函数在哪定义,只看函数调用方式
普通调用 ==> window对象中的this ==> .前面是谁就是谁定时器中的this ==> window事件处理函数 ==> 事件源箭头函数中的this ==> 该作用域外部作用域的this构造函数中的this ==> 本次调用 被自动创建的对象 //在全局使用this指向window console.log(this); // window console.log(window); // window console.log(window === this); // true // 函数中this指向 // 1. 普通调用 this===> window function fn() { console.log(this); // window } fn(); // 2. 对象调用 function fn() { console.log(this); // {name: '小花', f: ƒ} console.log(this.name); // 小花 } // 把fn这个函数当做一个值存在对象中键名为f的位置 var obj = { name: "小花", f: fn, }; obj.f(); // 3. 定时器调用 this 指向window function fn() { console.log(this); // window } setTimeout(fn, 2000); var username = "tom"; function fn() { console.log(this); // window console.log(this.username); // tom } var obj = { username: "小花", f: fn, }; setTimeout(obj.f, 2000); // 4. 事件处理函数 this指向事件源 function fn() { console.log(this); // #document } document.onclick = fn; (2) 如何改变this的指向方法 1. call()方法语法:函数名.call(参数)
参数:
参数1:该函数内的this指向(新指向)参数2:依次给函数进行形参赋值特点:立即调用函数
2. apply()方法语法:函数名.apply(参数1, 参数2)
参数:
参数1:该函数内的this指向(新指向)参数2:是一个数组,内部的每一项都是给函数形参赋值特点:立即调用函数
3. bind()方法语法:函数名.bind(参数)
参数:
参数1:该函数内的this指向(新指向)从参数2开始,依次给函数的形参赋值特点:
不会立即调用函数,而是返回一个新函数有一个返回值,是一个和原始函数一模一样的新函数,只不过this被锁死了 var name = 'zjk'; function fun() { console.log (this.name); } var obj= { name: 'jake' }; fun(); // zjk fun.call(obj); //Jake (3).改变this指向的方法有什么区别 三者都可以改变函数this对象的指向三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入bind是返回绑定this之后的函数,apply、call 则是立即执行 (4) call apply bind原理理解call
第一个参数为null或者undefined时,this指向全局对象window,值为原始值的指向该原始值的自动包装对象,如 String、Number、Boolean为了避免函数名与上下文(context)的属性发生冲突,使用Symbol类型作为唯一值将函数作为传入的上下文(context)属性执行函数执行完成后删除该属性返回执行结果 Function.prototype.myCall = function(context,...args){ let cxt = context || window; //将当前被调用的方法定义在cxt.func上.(为了能以对象调用形式绑定this) //新建一个唯一的Symbol变量避免重复 let func = Symbol() cxt[func] = this; args = args ? args : [] //以对象调用形式调用func,此时this指向cxt 也就是传入的需要绑定的this指向 const res = args.length > 0 ? cxt[func](...args) : cxt[func](); //删除该方法,不然会对传入对象造成污染(添加该方法) delete cxt[func]; return res; }apply
前部分与call一样
第二个参数可以不传,但类型必须为数组或者类数组
Function.prototype.myApply = function(context,args = []){ let cxt = context || window; //将当前被调用的方法定义在cxt.func上.(为了能以对象调用形式绑定this) //新建一个唯一的Symbol变量避免重复 let func = Symbol() cxt[func] = this; //以对象调用形式调用func,此时this指向cxt 也就是传入的需要绑定的this指向 const res = args.length > 0 ? cxt[func](...args) : cxt[func](); delete cxt[func]; return res; }bind
需要考虑:
bind() 除了 this 外,还可传入多个参数;bind 创建的新函数可能传入多个参数;新函数可能被当做构造函数调用;函数可能有返回值;实现方法:
bind 方法不会立即执行,需要返回一个待执行的函数;(闭包)实现作用域绑定(apply)参数传递(apply 的数组传参)当作为构造函数的时候,进行原型继承 Function.prototype.myBind = function (context, ...args) { //新建一个变量赋值为this,表示当前函数 const fn = this //判断有没有传参进来,若为空则赋值[] args = args ? args : [] //返回一个newFn函数,在里面调用fn return function newFn(...newFnArgs) { if (this instanceof newFn) { return new fn(...args, ...newFnArgs) } return fn.apply(context, [...args,...newFnArgs]) } } (5) 箭头函数没有this箭头函数内的this 就是该作用域外部作用域的this 箭头函数外面的函数this是啥,箭头函数this就是啥
注意: 事件处理函数不要用箭头函数,会改变this指向
三. 讲讲Map和Set?1.Map的key相比较普通对象来说更为灵活,普通对象的key只能以基础数据类型作为key值,并且所有传入的key值都会被转化成string类型,而Map的key可以是各种数据类型格式。
2.Set可以讲讲它去重的特性。
数据结构 SetES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成 Set 数据结构。
由于Set是伪数组,并且伪数组里面的值都是唯一的,所以可以用在数组去重中
const s = new Set() const arr = [7, 2, 3, 4, 2, 5, 5]; arr.forEach(item => { s.add(item) }); console.log(s); // Set(5) {7, 2, 3, 4, 5} console.log([...s]); // (5) [7, 2, 3, 4, 5] // 简化为 const set = new Set([7, 2, 3, 4, 2, 5, 5]); [...set]// [7, 2, 3, 4, 5] (1) 创建 Set 数据结构语法:
var s = new Set([数据1, 数据2, 数据3....]) (2) Set 数据结构的属性和方法属性:size
方法:add()、has()、delete()、clear()、forEach()
size 属性
该数据结构中有多少个数据
语法:数据结构.size
// eg: const s = new Set([100, 200, 300, 200]); console.log(s.size); // 3add() 方法
向该数据结构添加内容
语法:数据结构.add(数据)
// eg: const s = new Set([100, 200, 300]); s.add(500) s.add(100) console.log(s); // Set(4) {100, 200, 300, 500}has() 方法
查找Set中是否有该数据
语法:数据结构.has(数据)
true 该数据结构内有该数据 false 该数据结构内没有该数据
// eg: const s = new Set([100, 200, 300]); console.log(s.has(100)); // true console.log(s.has(500)); // falsedelete()方法
删除数据
语法:数据结构.delete(数据)
// eg: const s = new Set([100, 200, 300]); s.delete(100); console.log(s); // Set(2) {200, 300}clear() 方法
清除该数据结构内所有内容
语法:数据结构.clear()
// eg: const s = new Set([100, 200, 300]); s.clear(); console.log(s); // Set(0) {size: 0}forEach() 方法
语法 :数据结构.forEach(function(value, key, origin){})
// eg: const s = new Set([100, 200, 300]); s.forEach(function(value, key, origin){ console.log(value, key, origin); // 100 100 Set(3) {100, 200, 300} }); (3) Set中判断两个值是否不同向 Set 加入值的时候,不会发生类型转换,所以5和"5"是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。
let set = new Set(); let a = NaN; let b = NaN; set.add(a); set.add(b); set // Set {NaN}上面代码向 Set 实例添加了两次NaN,但是只会加入一个。这表明,在 Set 内部,两个NaN是相等的。
另外,两个对象总是不相等的。
let set = new Set(); set.add({}); set.size // 1 set.add({}); set.size // 2上面代码表示,由于两个空对象不相等,所以它们被视为两个值。
数据结构 MapMap 数据结构:类似于对象的数据结构,它的key可以是任何数据类型,可以被看做为一个 值 = 值 的数据结构
(1) Map 基本概念ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
(2) Map 特征 Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。Map 是 ES6 中引入的一种新的数据结构 (3) Maps 和 Objects 的区别 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。 (4) 创建一个 Map数据结构语法:
var m = new Map( [ [key, value], [key, value] ] ) (5) Map 数据结构的属性和方法属性:size
方法:set()、get()、has()、delete()、clear()、forEach()
size 属性
该数据结构内有多少个数据
语法:数据结构.size
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); console.log(m.size); // 2set() 方法
向该数据结构添加内容
语法:数据结构.set(key, value)
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.set('time', '两年半'); console.log(m); // Map(3) {'name' => 'zs', 'age' => 18, 'time' => '两年半'}get() 方法
语法:数据结构.get(key)
返回值:该数据结构内key对应的value
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); console.log(m.get('name')); // zshas() 方法
该数据结构中是否有该数据
语法:数据结构.has(key)
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); console.log(m.has('name')); // truedelete() 方法
删除该数据结构内某一个数据
语法:数据结构.delete(key)
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.delete('name'); console.log(m); // Map(1) {'age' => 18}clear() 方法
清除该数据结构里面的所有内容
语法:数据结构.clear()
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.clear(); console.log(m); // Map(0) {size: 0}forEach()
语法:
数据结构.forEach(function(value, key, origin){}) // eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.forEach(function (value, key, origin) { console.log(value, key, origin); // zs name Map(2) {'name' => 'zs', 'age' => 18} // 18 'age' Map(2) {'name' => 'zs', 'age' => 18} }) 四. new的过程发生了什么 首先创建了一个新对象设置原型,将对象的原型设置为函数的prototype对象让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象 五. localStorage sessionStorage cookies 有什么区别 (1) 什么是会话级存储window.sessionStorage
特点:
生命周期结束为关闭浏览器窗口在同一窗口(页面)下数据可以共享(不能跨页面共享)以键值对的形式存储使用 (2) 什么是持久性存储window.localStorage
特点:
生命周期永久生效,除非手动删除否则关闭页面也会存在可以多窗口(页面)共享(同一浏览器可以共享)以键值对的形式存储使用 (3) 什么是cookie特点:
只能存储字符串,并且有自己的固定格式
key=value;key2=value2;key3=value3cookie 存储有大小限制
存储空间:4kb左右
存储的时效性
默认是会话级别,可以手动设置过期时间
操作依赖服务器
本地打开的页面不能操作cookie
必须用服务器打开
跟随前后端请求自动携带
前后端都可以操作
存储的时候依赖域名
使用哪个域名存储,就用哪个域名
不能跨域名通讯
(4) cookie和storage的区别出现时间
cookie 在JavaScript刚出现的时候就有了
storage 是H5新增的新特性
存储大小
cookie 4kb
storage 20M
前后端交互
storage 存储的数据不会跟随页面携带
cookie 存储的数据会跟随页面请求自动携带
前后端操作
storage 只能利用JavaScript操作
cookie 前后端都可以操作
过期时间
cookie 默认是会话级,可以手动设置过期时间
storage 不能手动设置过期时间
(5) localStorage和sessionStorage的区别过期时间
localStorage 永久存储
sessionStorage 临时存储
跨页面通讯
localStorage 直接跨页面共享数据
sessionStorage 只能是从当前窗口跳转的
共同点
只能存字符串,不能存复杂数据类型
结束语:
希望对您有一点点帮助,如有错误欢迎小伙伴指正。 👍点赞:您的赞赏是我前进的动力! ⭐收藏:您的支持我是创作的源泉! ✍评论:您的建议是我改进的良药! 一起加油!!!💪💪💪
前端高频面试题—JavaScript篇(二)由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“前端高频面试题—JavaScript篇(二)”