JavaScript知识点
(8)不改变原数组的方法
- join 变成字符
- Slice,截取
- concat 合并数组
(三)栈和堆的区别
(1)栈由编译器自动分配释放空间,堆一般由程序员分配释放 ;
(2)栈存放在一级缓存中,调用完毕立即释放 ;
(3)堆则是在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定;
【执行上下文与作用域】
1.什么是作用域,什么是作用域链? ⭐⭐⭐⭐
- 作用域:规定变量和函数的可使用范围称为作用域
- 作用域链:每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链
2.什么是执行上下文?什么是执行上下文栈⭐⭐⭐⭐
(1)执行上下文:
执行上下文分为:全局执行上下文和函数执行上下文 、eval执行上下文
- 全局执行上下文(window)
创建一个全局的window对象,并规定this指向window,执行js的时候就压入栈底,关闭浏览器的时候才弹出 - 函数执行上下文(创建阶段+执行阶段)
每次函数调用时,都会新创建一个函数执行上下文
函数执行上下文分为创建阶段和执行阶段- 创建阶段:函数环境会创建变量对象:
- arguments对象(并赋值)、函数声明(并赋值);
- 变量声明(不赋值),函数表达式声明(不赋值);
- 会确定this指向;会确定作用域
- 执行阶段:变量赋值、函数表达式赋值,使变量对象编程活跃对象
- 创建阶段:函数环境会创建变量对象:
- eval执行上下文
(2)执行栈: - 首先栈特点:先进后出
- 当进入一个执行环境,就会创建出它的执行上下文,然后进行压栈,
当程序执行完成时,它的执行上下文就会被销毁,进行弹栈。 - 栈底永远是全局环境的执行上下文,
栈顶永远是正在执行函数的执行上下文 - 只有浏览器关闭的时候全局执行上下文才会弹出
【单线程,同步异步】
(一)线程
为什么JS是单线程的? ⭐⭐⭐⭐⭐
- 这主要和js的用途有关,js是作为浏览器的脚本语言,主要是实现用户与浏览器的交互,以及操作dom
- 如果是多线程的话,假如有一个线程要修改一个dom元素,另一个线程要删除这个dom元素,导致浏览器不知道该听谁的
(二)异步函数Promise
说说 Promise 的原理?你是如何理解 Promise 的? ⭐⭐⭐⭐⭐
promise相对于async…await的优缺点⭐⭐⭐
- promise
- 无法取消
- 错误无法被try…catch捕获,但是可以被catch方法捕获
- async传染力比较强
fetch优缺点 ⭐⭐⭐⭐
- fetch脱离了XHR,基于promise实现
- 对某些错误不会reject,比如状态码400、500
- fetch不支持超时timeout处理
- fetch默认不携带cookie,需要手动配置
- fetch没有办法监测请求进度,而xhr可以
(三)宏任务和微任务
1. setTimeout,setInterval,requestIdleCallback 和 requestAnimationFrame 还有 Promise,这几个有什么区别
| 名称 | 描述 |
|---|---|
setTimeout | 用于在指定的时间后执行一次回调函数。它会在延迟一段时间后将回调函数添加到事件队列,并在主线程空闲时执行。 可以通过clearTimeout取消计时器。 |
setInterval | 用于每隔一段时间重复执行一次回调函数。它会在每个周期间隔结束后将回调函数添加到事件队列,并在主线程空闲时执行。可以通过clearInterval取消周期性执行。 |
requestIdleCallback | 用于在主线程空闲时执行回调函数,以避免影响关键交互和动画。它会在浏览器空闲的时候调用回调函数,尽量利用未使用的计算资源。可以通过cancelIdleCallback取消回调。 |
requestAnimationFrame | 用于在下一帧绘制之前执行回调函数,通常用于执行动画或其他需要与浏览器绘制同步的任务。它会在浏览器进行下一次重绘之前调用回调函数。 在适当的时候使用cancelAnimationFrame取消回调。 |
Promise | 是一个表示异步操作最终完成或失败的对象。通过Promise,可以更容易地处理异步操作的结果,避免回调地狱。可以通过then和catch等方法链式调用,也可以使用async/await语法进行处理。 |
适用场景:
setTimeout和setInterval适合处理简单的定时任务;requestIdleCallback和requestAnimationFrame则更适合处理需要精确时间控制或优化性能的任务;Promise则是一种通用的异步编程模型,用于处理异步操作的结果和错误。
(四)手写 ajax⭐⭐⭐⭐
- 创建 XMLHttpRequest对象xhr:
xhr = new XMLHttpRequest() - 建立一个 HTTP 请求:
xhr.open(method, url, async, username, password) - 发送请求:
xhr.send(body) - 接收响应数据:
xhr.responseText - 设置请求头(POST):
- 使用
setRequestHeader()方法设置请求消息的内容类型为“application/x-www-form-urlencoded”,它表示传递的是表单值,
- 使用
【ES6 知识点】
【模块化】
1. ES6和commonjs的区别⭐⭐⭐
Commonjs、AMD、CMD、UMD、ESM 都有什么区别
(1)Commonjs(同步模块加载)
- 同步模块加载,需要使用 require()指定依赖,
- CommonJS 模块语法不能在浏览器中直接运行,不适合前端,后端 nodejs 可以使用 commonjs。
- 使用方式:
module.exports = xxx
require('xxx')
(2)AMD(Asynchronous module definition:异步模块定义)
(AMD/CMD/UMD 适用前端 异步执行)
-
AMD 模块实现的核心是用函数包装模块定义。这样可以防止声明全局变量,并允许加载器库控制何时加载模块
-
异步运行:异步模块定义,主要采用异步的方式加载模块,模块的加载不影响后面代码的执行。所有依赖这个模块的语句都写在一个回调函数中,模块加载完毕,再执行回调函数
-
AMD要求在使用前需要先把所有的模块都写出来
-
使用方式:
define(["a","b","c","d","e"],function(a,b,c,d,e){
// 相当于在前面声明并初始化了要用到的所有模块
a.dosomething()
if(false) {
// 即使没有用到模块 b,也会提前执行
b.dosomething()
}
})
(3)CMD(Common Module Definition:通用模块定义)
- 异步运行
- seajs 规范
- AMD 和 CMD 的差别是:
- AMD 是依赖前置(把依赖放在前面)、提前执行(即使没有用到某个模块,也会提前执行)
- CMD依赖就近、延时执行(用到的时候在声明依赖)
- 使用方式:
define(function(require, exports, module){
var a = require("./a") //需要的时候声明
a.dosomething()
if(false) {
var b = require("./b")
b.dosomething()
}
})
(4)ESM(ES Module)
- 使用
export 、 export default来导出模块,使用import来引入模块 - ESM 和 commonjs 的区别主要在于:
- commonjs 是运行时加载 ;ESM 是编译时加载
- commonjs 是同步加载模块;ESM 是异步加载模块
- commonjs 是对值的浅拷贝;ESM 是对值的引用,而且不可修改(直接地址不可修改,类似于 const)。
2. JS模块包装格式有哪些?⭐⭐⭐
commonjs、AMD、CMD
3. require 和 import的区别?⭐⭐⭐
| 区别 | require | |
|---|---|---|
| 调用时机 | require 是运行时调用,所以可以放在任何地方 | Import 是编译时调用,所以必须放在文件的开头 |
| 使用方式 | require 需要使用:module.exports = fs(导出全部)或者exports.fs = xxx(导出部分) | import 用 :export default(导出全部) 或者export const xx(导出部分) |
| 解构赋值 | require 是赋值的过程 | import 是解构的过程 |
【集合引用类型】
【Array】
数组的常用方法
- every 和 some()
every()和some()方法是数组的逻辑判定:它们对数组元素应用指定的函数进行判定,返回true或false。- every()方法:当且仅当针对数组中的所有元素调用判定函数都返回true,它才返回true
- some()方法:当数组中至少有一个元素调用判定函数返回true,它就返回true;并且当且仅当数值中的所有元素调用判定函数都返回false,他才返回false
- find() 和 findIndex()
- fill()
- includes()
- flat()
数组的成员有时还是数组,Array.prototype.flat()用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组,对原数据没有影响。
flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将flat()方法的参数写成一个整数,表示想要拉平的层数,默认为1。如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数
如果原数组有空位,flat()方法会跳过空位。
const numbers = [1, 2, [3, 4, [5, 6]]];
// Considers default depth of 1
numbers.flat();
> [1, 2, 3, 4, [5, 6]]
// With depth of 2
numbers.flat(2);
> [1, 2, 3, 4, 5, 6]
// Executes two flat operations
numbers.flat().flat();
> [1, 2, 3, 4, 5, 6]
// Flattens recursively until the array contains no nested arrays
numbers.flat(Infinity)
> [1, 2, 3, 4, 5, 6]
[ 延伸问题]
(1)js 遍历数组的方法⭐⭐⭐⭐⭐
reduce、map、filter、every、some、foreach.
foreach 和 map 有什么区别⭐⭐⭐⭐
- foreach 没有返回值,一般如果用来遍历修改原数组的话可以用 foreach 方法
(2)数组可以改变原数组的方法⭐⭐⭐⭐⭐
| 序号 | 方法名 | 作用 | 返回值 | 备注 |
|---|---|---|---|---|
| 头部操作 | shift | 把数组的第一个元素从其中删除 | 返回第一个元素值 | - |
| unshift | 向数组的开头添加一个或更多元素 | 返回新的长度 | - | |
| 尾部操作 | push | 向数组的末尾添加一个或多个元素 | 返回新的长度 | - |
| pop | 移除最后一个数组元素 | 返回删除的元素 | 会改变数组的长度 | |
| 顺序 | sort | 对数组的元素进行排序 | - | array.sort(sortfunction)在原数组上进行排序 |
| reverse | 用于颠倒数组中元素的顺序 | - | array.reverse()在原数组上进行排序 | |
| ④ | splice | 用于添加或删除数组中的元素 | 返回删除元素的数组 | array.splice(index,howmany,item1,.....,itemX) |
- sort
- 升序:
array.sort(function(a,b){return a-b}) - 降序:
array.sort(function(a,b){return b-a})
- 升序:
array.splice(index,howmany,item1,.....,itemX)- index:从0开始,第一个是0位
- howmany:删除的个数/0
- item1,.....,itemX:插入的数据...
【Map】~对象
参考链接:
Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数Map可以接受一个数组作为参数。
- JSON字符串要转换成Map可以先利用JSON.parse()转换成数组或者对象,然后再转换即可。
Map对象的属性和方法
Map对象的属性:
- size:返回Map对象中所包含的键值对个数
Map对象的方法:
-
set(key, val):向Map中添加新元素
-
get(key):通过键值查找特定的数值并返回
-
has(key):判断Map对象中是否有Key所对应的值,有返回true,否则返回false
-
delete(key):通过键值从Map中移除对应的数据
-
clear():将这个Map中的所有元素删除 遍历方法:
-
keys():返回键名的遍历器
-
values():返回键值的遍历器
-
entries():返回键值对的遍历器
-
forEach():使用回调函数遍历每个成员
Map和Object的区别
- 一个Object 的键只能是字符串或者 Symbols,但一个Map 的键可以是任意值。
- Map中的键值是
有序的(FIFO 原则: first in,first out先进先出法”),而添加到对象中的键则不是。 - Map的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
- Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
【Set】~数组
Map对象的属性和方法
Set 对象允许你存储任何类型的值,无论是原始值或者是对象引用。它类似于数组,但是
成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成Set 数据结构。Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构作为参数,用来初始化。
Set中的特殊值:
Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。有几个特殊值需要特殊对待:
- +0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复
- undefined 与 undefined 是恒等的,所以不重复
NaN 与 NaN 是不恒等的,但是在 Set 中认为NaN与NaN相等,所有只能存在一个,不重复。{} {} 两个空对象的指针不一样,所以会重复
Set实例对象的属性:
- size:返回Set实例的成员总数。
Set实例对象的方法:
- add(value):添加某个值,返回 Set 结构本身(可以链式调用)。
- delete(value):删除某个值,删除成功返回true,否则返回false。
- has(value):返回一个布尔值,表示该值是否为Set的成员。
- clear():清除所有成员,没有返回值。
遍历方法:
和map一样
(由于Set结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。)
Set 对象作用
- 数组去重(利用扩展运算符)
- 合并两个set对象:
- 交集
new Set([...a].filter(x => b.has(x)))
let a = new Set([1, 2, 3])
let b = new Set([2, 3, 6])
let intersect = new Set([...a].filter(x => b.has(x))) // {2, 3} 利用数组的filter方法。
- 差集
new Set([...a].filter(x => !b.has(x)))
let a = new Set([1, 2, 3])
let b = new Set([4, 3, 2])
let difference = new Set([...a].filter(x => !b.has(x))) // {1}
Map和Set的区别
- Map是键值对,Set是值的集合,当然键和值可以是任何的值;
- Map可以通过get方法获取值,而set不能因为它只有值;
- 都能通过迭代器进行for…of遍历;
Set的值是唯一的可以做数组去重,Map由于没有格式限制,可以做数据存储;- map和set都是stl中的关联容器,map以键值对的形式存储,key=value组成pair,是一组映射关系。set只有值,可以认为只有一个数据,并且set中元素不可以重复且自动排序
【对象、类与面向对象编程】
(一)对象
[ 延伸问题 ]
(1)字面量创建对象和new创建对象有什么区别?new内部都实现了什么,手写一个new⭐⭐⭐⭐⭐
new和字面量创建对象的区别:
1.字面量创建对象,不会调用Object构造函数,简洁且性能更好;
2.new Object() 方式创建对象本质上是方法调用,涉及到在proto链中遍历该方法,当找到该方法后,又会生产方法调用必须的 堆栈信息,方法调用结束后,还要释放该堆栈,性能不如字面量的方式。
new的工作原理(new在执行时会做的四件事):
-
创建:创建一个新的空对象
let obj = {} -
继承:继承了构造函数的原型
obj.__proto__ = fn.prototype
(即 让新对象的__proto__指向原函数的prototype)。 -
执行:执行构造函数方法
let result = fn.apply(obj, args)
把构造函数方法的属性和方法都添加到this引用的对象中,让this指向这个新的对象 -
返回:返回这个新对象
return result instanceof Object ? result : obj(如果构造函数中没有返回新对象,那么返回this,即创建新对象;否则,返回构造函数中返回的对象。).
(2)手写new
function myNew(fn, ...args) {
// 创建一个空对象
let obj = {}
// 使空对象的隐式原型指向原函数的显式原型
obj.__proto__ = fn.prototype
// 执行构造函数里面的代码(执行结果保存起来作为result ),
// 给这个新对象添加属性和方法。
let result = fn.apply(obj, args)// 让this指向这个新的对象obj。
// 返回
// 判断执行函数的结果是不是null或Undefined,
// 如果是则返回之前的新对象,如果不是则返回result
return result instanceof Object ? result : obj
}
【其他】
什么是防抖?什么是节流?手写一个⭐⭐⭐⭐⭐
setTimeOut第三个参数是什么?⭐⭐⭐⭐⭐
可以作为参数传给前面的函数,一般用于 for 循环赋值
什么是暂时性死区?(先使用后定义)⭐⭐⭐⭐⭐
暂时性死区是指,当进入一个作用域,我去使用一个变量名,而这个变量名已经存在了,但是是不可获取的,就会报错,造成暂时性死区问题;
比如一个作用域下面使用了 let 定义了 x,但是在定义之前就使用了 x,就会报错;暂时性死区意味着 typeof 也不是绝对安全的操作
x = '123'; // 报错
let x = 1
---------------------
typeof y; // 报错
let y = 123
?? 如何实现大文件上传?⭐⭐⭐⭐
使用 input 接受大文件,使用file.slice进行分割分块上传(制定好一个块的大小,然后进行分割),等所有块上传完毕之后,promise.all(),运行成功回调
Object.keys和Object.getOwnPropertyNames有什么区别?⭐⭐⭐
- Object.keys只列出非原型上可枚举的key值
- 而Object.getOwnPropertyNames列出非原型上的所有key值(Symbol除外)
??如何配置rem⭐⭐⭐
思路:给html设置一个根字体的大小html{font-size:' + rootFontSize + 'px!important}
//rem适配
(function () {
const styleEle = document.createElement('style');
const docWidth = document.documentElement.clientWidth;
const rootFontSize = docWidth / 16;
styleEle.innerHTML = 'html{font-size:' + rootFontSize + 'px!important}';
document.head.appendChild(styleEle);
})()
倒计时用setimeout来实现还是setInterval⭐⭐⭐⭐
- setTimeout
- 因为假如用setInterval的话,该程序执行需要105ms,而设置的间隔为100ms,则还没运行完最后的那5毫秒就会运行下一次的函数
??秒传、分片传输、断点传输⭐⭐⭐⭐
- 秒传
文件上传前,服务器先对文件做MD5校验,如果服务器上有同样的文件,则返回一个新地址,如果不想秒传也可以,修改文件中的内容就可以了(改名字不行) - 分片传输
利用Blob提供的slice方法把大文件分割为一个个小文件分别传输。全部上传完成时候由服务端进行归总整合 - 断点传输
在分片上传的基础上,分成一个个小文件之后,每个小文件上传完毕之后对其进行状态的存储(localStorage),如果中间发生网络断线或者刷新,下次可以接着上次的进度上传
e.target和e.currentTarget的区别⭐⭐⭐
- e.target指向的是触发事件的元素;(点击的元素)
- e.currentTarget指向的是添加监听事件的元素;(绑定方法的元素)
<button type="button" class="btn btn-default" attr="workstep">
<i class="icon-test"></i>
<p style="display: inline-block;vertical-align:top;line-height: 28px;">按钮</p>
</button>
点击p标签,target是p,currenttarget是button
jquery 如何实现链式调用⭐⭐⭐
- 在 jQuery 中,如果对同一个对象进行多种操作,则可以使用链式调用的语法。
- 链式调用是 jQuery 中经典语法之一,不仅节省代码量,还可以提高网站的性能。
let fun = {
fun1: function() {
console.log("fun1");
return this;
},
fun2: function() {
console.log("fun2");
return this;
},
fun3: function() {
console.log("fun3");
return this;
}
}
//链式调用
fun.fun1().fun2().fun3();
??JS性能优化的方式⭐⭐⭐⭐⭐
- 垃圾回收
- 闭包中的对象清除
- 防抖节流
- 分批加载(setInterval,加载10000个节点)
- 事件委托
- 少用with
- requestAnimationFrame的使用
- script标签中的defer和async
- CDN