赞
踩
number, string, boolean, undefined, null, symbol, bigint, object
其中symbol是es6新增的
bigInt是es11新增的
太多了,说常用的,全面一点的在这里
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects
NaN | undefined | globalThis | object | arguments | Json |
function | boolean | symbol | error | Proxy | Set |
number | bigInt | Math | Date | Reflect | Promise |
string | EegExp | Array | Map |
3.1 JSON 是一种基于文本的轻量级的数据交换格式。它可以被任何的编程语言读取和作为数据格式来传递。
3.2 键值必须加双引号,值不能是函数,也不能是undefined/NaN
3.3 最简单的深拷贝,可以使用JSON.parse()和JSON.stringify()来嵌套使用
concat | fill | filter | find/findLast | findIndex/findLastIndex | forEach |
indexOf/lastIndexOf | isArray | join | map | pop | push |
reduce | reverse | shift | unshift | slice | sort |
splice | toString | values | some | Array.of | every |
dom文档对象模型,是一种以平台和语音无关的api,用于处理网页内容
bom浏览器对象模型,是描述对象与对象之间层次关系模型,其中window对象是bom的顶层对象,其他对象都是该对象的子对象,如:location, navigator, screen, document
6.1 this在全局作用域下指向的是window
6.2 this的绑定规则有4种
默认绑定
隐式绑定
显式绑定
new绑定
绑定优先级new > 显式 > 隐式 > 默认
https://mp.weixin.qq.com/s/hYm0JgBI25grNG_2sCRlTA
var是函数作用域,let是块作用域
var可以声明提升,let不可以,“因为在解析代码之前,js引擎会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用为声明的变量。在let声明之前的执行瞬间被称为“暂时性死区”(其实let也存在提升,但是不允许访问)
var会成为window对象的属性,let则不会“使用let在全局作用域中声明的变量不会成为window对象属性”
在for循环的中var定义的变量会渗透到循环体外,let则不会
“js引擎会为for循环中let声明分别创建独立的变量实例,而且let和const很相似,不能用const来声明迭代变量(因为迭代变量会自增)”
let和const不存在变量提升
验证变量是否会被提升,声明的变量输出的undefined,不是变量提升(let)输出Reference Error
重复的var声明会被忽略,重复的let声明会抛出syntaxErrorr
重点:执行到let时,其实是提升了,已经被创建出来了,但是不给访问,也就是上面所说的暂时性死区
对闭包的定义大概就是,其实js每创建一个函数都可以说是闭包
但是大家对闭包的理解是,函数内部访问到了函数外的自由变量,那么就可以称为闭包
什么是回流?(回流也称为重排)浏览器必须重新修改页面或者部分页面就是回流
例如:删除/新增dom节点,改变css的宽高等,这些都会引起回流
什么是重绘?可以理解改变background-color这些css样式,不影响dom或者布局就是重绘
这里附上一个链接,看浏览器渲染过程的1.3(回流)和1.4(重绘)
https://blog.csdn.net/qq_51657072/article/details/122985137
所以,回流一定会引起重绘,重绘不一定引起回流
这个用语言描述有点抽象,建议看视频
宏任务包含script(整体代码) setTimeout setInterval
微任务包含Promise.then Object.observe MutationObserver
这里从操作系统说起,简单说
可以理解为:进程就行相当于每打开一个软件,就是一个进程,因为这个软件在内存中运行(在任务管理器中可查看),有些软件是多进程,例如浏览器,当打开n个网页,那么就是n个进程。
线程就是比进程还小的单位,顺序执行的过程。
(js的事件循环?这里还有node的事件循环不讲)
2.1 在一个进程内执行(一个网站内)js代码,由于js是单线程的
2.2 当遇到网络请求,settimeout等代码,交给当前进程的其他线程执行,当其他线程执行结果返回到事件队列(微任务/宏任务),在执行任何一个宏任务时,都会查看微任务是否为空,不为空的话,先执行微任务在执行宏任务。
2.3 当事件队列执行结束后,会返回给js线程, 那么就这样就形成了一个闭环,就称为事件循环
js线程-->浏览器其他线程-->事件队列-->js线程
cookie:cookie存储在客户端,可以和服务器建立连接,生命周期是如果设置了时间,那么就存储在硬盘cookie,默认是关闭浏览器自动删除(这个就是存储在内存上)
webStorage包含localstorage和sessionstorage
localstorage:存储在客户端,生命周期数据永久保存,需要手动清理缓存
sessionstorage:存储在客户端,生命周期是刷新页面还是会保存数据,当关闭浏览器,关闭页面,跳转页面,数据失效
即:当发现这块内存再也没有使用会被标记,然后等到下一次回收的时间,把这块清除
例子:let obj = {},执行一段代码后后,我把obj = null,这个过程就是我在内存中创建一个内存放{},用完这个{}后,我把obj变量赋值null,那么在内存中,就没有指向{},那么这个{}就会被标记上,下一次内存回收就把这个{}清除
即:当创建一个变量并赋值的时候为1,当这个变量被赋值其他内容就减1,当这个变量变为0时,就清除
要么接收一个函数,要么返回一个函数
像setTimeout就可以说是一个高阶函数
ReferenceError | 引用错误,使用了未声明的变量, 无效引用 |
RangeError | 内置错误, 数值变量或参数超出其有效范围 |
TypeError | 类型错误, 变量或参数不属于有效类型 |
SyntaxError | 语法错误 |
EvalError | 错误原因与 eval() 有关 |
URIError | 给 encodeURI() 或 decodeURI() 传递的参数无效 |
AggregateError | 创建一个 error 实例,其中包裹了由一个操作产生且需要报告的多个错误 |
InternalError | 创建一个代表 Javascript 引擎内部错误的异常抛出的实例。如:递归太多 |
es5之前分为全局作用域和局部作用域
es6之后,var属于函数作用域,let属于块级作用域,块级指的是{}
作用域是指内部定义的变量,外部没有反问权限
作用域链指当前作用域内查找引用,如果没找到,会向上一层接着找,层层向上直到全局作用域,这一过程被称为作用域链
词法分析,语法分析
左查询和右查询(LHS和RHS)
例:let a = 2,a就是左查询,2就右查询
左查询就是赋值后引用的值,即如果a在别的地方用到,其实a就是引用了这个源值为2,a就是左查询(赋值操作的目标是谁就是LHS)
右查询查询就是源值(谁是赋值操作的源头就是RHS)
作用域链就是根据左右查询一步步向上找的
细节: 函数声明会被提升,但是函数表达式却不会被提升,函数会首先被提升,然后才是变量
undefined表示一个变量被声明,被自动赋值
null表示空值,可以对一个对象的引用,可以用来释放一个对象
相同点
都是原始类型,保存在栈中变量本地
不同点
1.1 数据类型不一样,undefined是undefined,null是object
console.log(typeof undefined) // undefined
console.log(typeof null) // object
console.log(null == undefined) // true
console.log(null === undefined) // false
1.2 隐式转换不同
console.log(Number(null)) // 0
console.log(Number(undefined)) // NaN
console.log(22+null) // 22
console.log(22+undefined) // NaN
typeof 用于判断数据类型,返回值有number、string、boolean、function、undefined、object 六个
intanceof判断对象的实例
[] instanceof Array; //true
{} instanceof Object;//true
new Date() instanceof Date;//true
3.1 都可以循环数组,for in 输出的是数组的index下标,而for of 输出的是数组的每一项的值
const arr = [1,2,3,4]
for (const key in arr){
console.log(key) // 输出 0,1,2,3
}
for (const key of arr){
console.log(key) // 输出 1,2,3,4
}
3.2 for in 可以遍历对象,for of 不能遍历对象,只能遍历带有iterator接口的,例如Set,Map,String,Array
const object = { name: 'lx', age: 23 }
for (const key in object) {
console.log(key) // name,age
console.log(object[key]) // lx,23
}
for (const key of object) {
console.log(key) // 报错 Uncaught TypeError: object is not iterable
}
for in适合遍历对象,for of适合遍历数组
相同点
都可以传入三参,一参是当前元素,二参是索引,三参是整个数组
不同点
forEach()允许callback更改原始数组的元素,返回是undefined
map()会开辟新的内存空间,返回一个新的数组
相同点
都是动态修改this指向;都不会修改原先函数的this指向
不同点
5.1 执行方式不同
bind()是异步代码,改变后不会立即执行,而是返回一个新的函数
call()和apply()是同步代码,改变后立即执行
5.2 传参不同
call()和bind()是逐个逐个传入
apply()是传入一个数组
5.3 修改this的性质不同
bind()是永久修改
call()和apply()是临时修改一次,再次调用时还是指向原来的this
===叫全等,值和类型都是一样
==叫等于,先判断两者类型是否相等,如果不相等就进行转化,如果类型相等就判断值是否相等
7.1 ES6 class 内部所有定义的方法都是不可枚举的;
7.2 ES6 class 必须使用 new 调用;
7.3 ES6 class 不存在变量提升;
7.4 ES6 class 默认即是严格模式;
7.5 ES6 class 子类必须在构造函数中调用super(),这样才有this对象;ES5中类继承的关系是相反的,先有子类的this,然后用父类的方法应用在this上。
__proto__(隐式原型)与prototype(显式原型)
__proto__是每个实例都有的属性,可以访问 [[prototype]] 属性
prototype是函数独有的属性
显式原型的作用: 用来实现基于原型得继承与属性的共享。
隐式原型的作用:构成原型链,同样用于实现基于原型的继承。当我们访问obj这个对象中的属性时,如果在obj中找不到,就沿着_proto_依次查找。
防抖debounce
在一段时间后,执行一次,若在这段时间内再次调用,则重新计算
如:设置一个按钮,设置200毫秒内执行一次,在这200毫秒如果没有再次点击则执行一次,如果点击了,那么从点击那刻开始再计算200毫秒
节流thorttle
在一定时间内,不论点击多少次,只会一次
如:英雄攻击野怪,平a速度,是一秒一个平a,你在一秒内按了10次,只会发出一个平a
①语法不同
②箭头函数是匿名函数,普通函数可以匿名可以具名
③箭头函数没有this,不能构造,this是指向上下文
④不能使用new操作符
⑤没有原型
⑥箭头函数可以使用闭包,递归,三元
⑦箭头函数不能绑定this
Promise解决了回调地狱问题,但promise的语法形成了一个then()形成了一个回调链,维护起来比较麻烦
而async/await的await在等的也是一个promise,等到了再执行下去,相对于promise的链式,简洁一些
两者都是非阻塞的
async await是基于Promise实现的,可以说是改良版的Promise,它不能用于普通的回调函数。
打断点不好调试,如果在一个promise的then()使用调试器的进步,调试器不会进入到后序的then(),因为调试器只能跟着同步代码
深拷贝就是开辟一块新的内存空间,存放复制过来的对象
const a = {'aaa': 1}
const b = JSON.parse(JSON.stringify(a))
b.aaa = 2
console.log(a, b)// {'aaa': 1} {'aaa': 2}
浅拷贝就是指针还是指向同一块内存空间,就是b对象复制了a对象,然后b对象修改了,a对象也会修改
const a = {'aaa': 1}
const b = a
b.aaa = 2
console.log(a, b) // {'aaa': 2} {'aaa': 2}
箭头函数是es6提出的,它没有原型(prototype),没有自己的this指向,更没有arguments,所以不能new一个箭头函数
new操作符实现理论
1.1 创建一个对象
1.2 将对象的__proto__属性指向prototype
1.3 将构造函数的this指向创建的属性
1.4 返回新的对象
use strict是es5新增的严格模式
目的是为了
2.11 消除js语法不合理,不严谨之处,减少怪异行为
2.12 消除代码的不安全之处
2.13 提高编译速度,为未来的新版本js做铺垫
在严格模式下
2.21 禁止使用with语句
2.22 禁止this指向全局对象
2.23 对象不能有重名属性
事件冒泡
指事件(从里到外),当一个元素接受到事件时,会把它接受的事件层层上传,直到document对象,事件冒泡值传递的事件而不是函数,即click,focus
如下图,当两个div都绑定了点击事件,点击内层的div时,内层的div会执行一次,然后外层的div跟着执行,如果点击外层的div,那么只会执行外层
事件捕获
指事件(从外到内),当外层的元素执行事件时,内层的元素会依次执行
如下图,当两个div都绑定了点击事件,点击外层div时,外层的点击事件执行一次,然后内层的点击事件跟着执行
<div class="外层">
<div class="内层"></div>
</div>
事件委托也叫事件代理,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
例子如图
不用事件委托,那么点击li的时候,先找到父级,再遍历li每个li都绑定了click,然后点击li的时候,才找到目标
委托事件就是在父级里绑定click,然后根据事件冒泡,被点击的那个li(事件源)传递到父级,这样就提高了性能
<ul id="父级">
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
这文章讲的好
https://www.cnblogs.com/liugang-vip/p/5616484.html
看概念第10题
js线程-->浏览器其他线程-->事件队列-->js线程
回调函数
一句话概括,就是把函数作为参数传递,如图
6.11 不会立即执行
6.12 是一个闭包
https://blog.csdn.net/weixin_47075145/article/details/125752446
function add(num1, num2, callback) {
var sum = num1 + num2;
callback(sum);
}
function print(num) {
console.log(num);
}
add(1, 2, print); //3
立即执行函数
立即执行函数执行完就被销毁,不需要添加函数名
函数该有的东西,立即执行函数都有
(function () {
console.log(1)
})() // 写法一
(function () {
console.log(1)
}()) // 写法二
会将传入的字符串当做 JavaScript 代码进行执行
永远不要使用 eval!
eval() 是一个危险的函数,它使用与调用者相同的权限执行代码。如果你用 eval() 运行的字符串代码被恶意方(不怀好意的人)修改,您最终可能会在您的网页/扩展程序的权限下,在用户计算机上运行恶意代码。更重要的是,第三方代码可以看到某一个 eval() 被调用时的作用域,这也有可能导致一些不同方式的攻击。相似的 Function 就不容易被攻击。
eval() 通常比其他替代方法更慢,因为它必须调用 JS 解释器,而许多其他结构则可被现代 JS 引擎进行优化。
此外,现代 JavaScript 解释器将 JavaScript 转换为机器代码。这意味着任何变量命名的概念都会被删除。因此,任意一个 eval 的使用都会强制浏览器进行冗长的变量名称查找,以确定变量在机器代码中的位置并设置其值。另外,新内容将会通过 eval() 引进给变量,比如更改该变量的类型,因此会强制浏览器重新执行所有已经生成的机器代码以进行补偿。但是(谢天谢地)存在一个非常好的 eval 替代方法:只需使用 window.Function。这有个例子方便你了解如何将eval()的使用转变为Function()。
用来表示一个独一无二的值
8.1 为什么需要Symbol?
为了避免第三方框架的同名属性被覆盖
8.2 特点
Symbol是基本数据类型,不要加new哦
后面括号可以传入一个字符串,只是一个标记,方便我们阅读,没有任何意义
类型转化的时候不可转化为数值
8.3 应用场景
在企业开发中如果需要对一些第三方的插件、框架进行自定义的时候
可能会因为添加了同名的属性或者方法, 将框架中原有的属性或者方法覆盖掉
为了避免这种情况的发生, 框架的作者或者我们就可以使用Symbol作为属性或者方法的名称
9.1 本地对象 ( native object )
由 es 实现提供并独立于宿主环境的任何对象。
本地对象可以理解为 ECMA-262 定义的类(引用类型)。
这些引用类型在运行过程中需要通过new来创建所需的实例对象。
包含:Object、String、Array、Date、Number、RegExp、Function、Boolean、Error等。
9.2 内置对象 ( built-in object )
由 es 实现提供并独立于宿主环境的,在程序开始执行就出现的对象。
本身就是实例化对象,开发者无需再去实例化。
所有内置对象都是本地对象的子集。包含:Global和Math。es5中增添了JSON这个存在于全局的内置对象。
9.3 宿主对象 ( host object )
由 ECMAScript 实现的宿主环境(如某浏览器)提供的对象(如由浏览器提供的 Window 和 Document),包含两大类,一个是宿主提供,一个是自定义类对象。
所有非本地对象都属于宿主对象。
对于嵌入到网页中的JS来说,其宿主对象就是浏览器提供的对象,浏览器对象有很多,如Window和Document等。包含:DOM 、BOM和自定义对象。
函数柯里化就是部分求值
只传递给函数一部分参数来调用它,让它返回一个新函数去处理剩下的参数
好处:参数复用,延迟调用
function sum1(a, b, c) {
let res = a + b + c
console.log(res)
}
sum1(1, 2, 3) // 6
// 柯里化
function sum2(a) {
return function(b) {
return function(c) {
return a + b + c
}
}
}
sum2(1)(2)(3)// 6
这里只说两种
①常用的是“标记清除”
即:当发现这块内存再也没有使用会被标记,然后等到下一次回收的时间,把这块清除
例子:let obj = {},执行一段代码后后,我把obj = null,这个过程就是我在内存中创建一个内存放{},用完这个{}后,我把obj变量赋值null,那么在内存中,就没有指向{},那么这个{}就会被标记上,下一次内存回收就把这个{}清除
②不常用的是“引用计数”
即:当创建一个变量并赋值的时候为1,当这个变量被赋值其他内容就减1,当这个变量变为0时,就清除
当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。
①使用原型链继承的弊端(常见的)
1.1 打印子函数,继承的属性是看不到的,因为打印的时候,只打印当前的可枚举属性,原型链上面的属性不会打印
1.2 创建a和b对象,在原型链上某个属性是引用类型,修改了a对象在原型链上引用类型某个值,b对象跟着变,说明a和b对象使用的是同一个引用类型
1.3 原型链继承不好实现传参数
解决方案:借用构造函数实现继承
这个借用也有弊端
一是,父类会调用两次
二是,原型对象多出属性,其实是没有必要的
function person () {
this.age = 0
}
function studect() {
this.name = 'abc'
}
studect.prototype = new person()
const obj = new studect()
console.log(obj.age, obj.name)// 0, abc
1. 关键字let和const
2. 解构
3. 扩展运算符
4. set()/WeakSet(),Map()/WeakMap()
5. Array.from()浅拷贝数组
6. find()和findIndex()
7. 模板字面量,在es6之前叫模板字符串
8. 箭头函数
9. 规范二进制和八进制写法
10. symbol
11. class类
新增数组方法如map,filter,some,reduce
promise
1. includes()判断是否包含某个值
2. 幂运算
1. Object.values
2. Object.entries
3. padStart()padEnd()
4. getOwnPropertyDescriptors()
5. Async/await
1. promise.prototype.finally()
2. Asynchronous Iteration 异步迭代器
1. flat()/flatMap()指定一个深度递归数组
2. Object.fromEntries()把键值对列表转换为一个对象
3. trimRight()/trimStart()/trimEnd()删除空格
4. Symbol.prototype.description只读属性
1. BigInt第七种数据类型
2. 空值合并操作符“??”双问号
3. 可选链,即obj.aaa?.bbb,如果aaa为空那么就停止搜索,不会报bbb的undefined
4. 规范全局this:globalThis
5. Promise.allSettled()
1. 数字过长可以使用“_”连接符,例:100_000_000_000
2. WeakRef()弱引用
3. replaceAll()字符串替换
新增promise.any()
class可以在最外层声明类成员,以前是在构造函数内声明
// es13之前
class Abc {
constructor() {
this.color = 'red'
}
}
const obj = new Abc()
console.log(obj.color) // red
// es13
class Abc {
color = 'red'
}
const obj = new Abc()
console.log(obj.color) // red
给类添加私有属性和变量操作符,在变量前面加#
支持在外层写await
支持定义静态成员和私有方法
class Person {
static #count = 0;
static getCount() {
return this.#count;
}
constructor() {
this.constructor.#incrementCount();
}
static #incrementCount() {
this.#count++;
}
}
const person1 = new Person();
const person2 = new Person();
console.log(Person.getCount()); // 2
使用in来判断某个对象是否拥有私有属性
使用at操作符来索引元素
// es13之前
const arr = ['a', 'b', 'c', 'd'];
console.log(arr[arr.length - 1]); // d
// es13
console.log(arr.at(-1)); // d
Object.hasOwn()方法
本身针对mvc编程,不符合前端的mvvm,现在有了fetch代替
配置和调用的方法有些混乱,对于事件的异步不太友好
可以说是ajax的替代品,在es6诞生的,使用了promise对象,fetch不是ajax的进一步封装,是原生js,没有使用xmlhttprequest对象
相对于ajax优点
语法简洁,基于标准的promise,支持async/await,脱离了xhr
缺点
没办法原生监测请求进度,而xhr可以
fetch不支持abort(拦截),不支持超时控制
浏览器端发起xmlhttprequests请求
node端发起http请求
支持promise api
监听请求和返回
客户端支持抵御xsrf攻击
promise属于js的一个基本内置对象,它的诞生是为了解决回调地狱的问题,在promise原型上绑定的then/catch方法对promise的使用形成了链式
promise实例三个状态,分别是pending(进行中),resolve(已完成),reject(已拒绝)
promise对象的常用方法9个
方法 | 描述 |
Promise.all() | 等待所有都完成,或者第一个失败就返回,不再执行后面 |
Promise.allSettled() | 不论有没报错,全部返回 |
Promise.any() | 有一个成功就算成功,失败的收集(实验性方法) |
Promise.race() | 有一个失败,就返回失败 |
Promise.reject() | 失败回调 |
Promise.resolve() | 成功回调 |
catch() | 捕抓失败 |
then() | 捕抓成功 |
finally() | 不论成功还是失败,都会执行该方法 |
async/await是es7提出,es8开始使用的一个新特性,当时的await只能写在async内
在es13(2022),await可以写在函数体外
async是函数前的一个修饰符,如果await不是等promise的话,跟普通函数没什么区别
async/await是为解决promise的链式调用,然代码更加简洁,增加它的可读可维护性
await等待的是一个表达式,它等的是一个实际的返回值
所以await不仅仅可以用于等promise对象,还可以等任何的表达式结果
await表达式的运行结果取决于它等的是什么
如果等的不是一个promise对象,那么就直接根据表达式结果返回
如果等的是一个promise对象,那么就会阻塞后面的代码,就要等promise对象的resolve,然后返回resolve值作为await的运行结果
后面的有空再更新...
若有收获,就点个赞吧
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。