前端学习
2023-03-30 15:05:48 0 举报
AI智能生成
FEE
作者其他创作
大纲/内容
js
1.数据类型
基本数据类型
string
number
最大安全数:Number.MAX_SAFE_INTEGER
Math.pow(2, 53) - 1
最小安全数:Number.MIN_SAFE_INTEGER
-(Math.floor(2, 53) - 1)
boolean
undefined
symbol
Symbol()不能用作构造函数,不能与new一起使用
全局注册表
第一次使用某字符串时,会检查全局注册表,发现不存在的符号,
就会新生成添加到注册表。后续使用相同的符号,返回符号实例。
就会新生成添加到注册表。后续使用相同的符号,返回符号实例。
Symbol.for('foo')
Symbol.for('foo') !== Symbol('foo') // false
Symbol.keyfor('foo')
keyfor会查询全局注册表,返回全局符号对应的字符串键,不是全局符号返回undefined
内置符号属性
Symbol.asyncIternator
for-await-of实现异步迭代器API的函数
const myAsyncIternable = new Object()
myAsyncIternable[Symbol.asyncIterator] = async function*(){
yield 'hello';
yield 'async';
}
(async () => {
for await (const x of myAsyncIternable){
console.log(x) // hello, async.
}
})()
myAsyncIternable[Symbol.asyncIterator] = async function*(){
yield 'hello';
yield 'async';
}
(async () => {
for await (const x of myAsyncIternable){
console.log(x) // hello, async.
}
})()
Symbol.iterator
for-of迭代器
Symbol.hasInstance
决定一个构造器对象是否认可一个对象是它的实例
ES6中,instanceof会使用Symbol.hasInstance来确定关系
function Foo(){}
let f = new Foo()
console.log(f instanceof Foo) // true
console.log(Foo[Symbol.hasInstance](f) // true)
let f = new Foo()
console.log(f instanceof Foo) // true
console.log(Foo[Symbol.hasInstance](f) // true)
Symbol.isConcatSpreadable
是个boolean值,表示是否应该用Array.prototype.concat()拍平数组
Symbol.match
boolean值,为true指定匹配的是正则表达式而不是字符串
为false表示不打算用作正则表达式对象
const reg = /foo/
console.log('/foo/'.startsWith(reg)) // Error
reg[Symbol.match] = false
console.log('/foo/'.startsWith(reg)) // true
console.log('/bar/'.endsWith(reg)) // false
console.log('/foo/'.startsWith(reg)) // Error
reg[Symbol.match] = false
console.log('/foo/'.startsWith(reg)) // true
console.log('/bar/'.endsWith(reg)) // false
Symbol.replace
正则表达式方法,该方法替换一个字符串匹配的子串,由String.prototype.replace()使用
'foobarbaz'.replace(/bar/, 'qux') // 'fooquxbaz'
Symbol.toPrimitive
一个方法,将对象转换为相应的原始值。(参数:string,number,default)
Symbol.toStringTag
一个字符串,用于创建对象的默认字符串描述,由Object.prototype.toString()使用
可自定义返回类型
class Bar{
constructor(){
this[Symbol.toStringTag] = 'Bar'
}
}
let bar = new Bar()
bar.toString() // [object Bar]
bar[Symbol.toStringTag()] // Bar
constructor(){
this[Symbol.toStringTag] = 'Bar'
}
}
let bar = new Bar()
bar.toString() // [object Bar]
bar[Symbol.toStringTag()] // Bar
bigInt
引用数据类型
object
array
function
regExp
date
数据类型判断
typeof
作为运算符,返回值不能作为JS类型系统的依据。
可以判断的数据类型
string
number
boolean
undefined
function
typeof null === 'object' // true
null的二进制为32位的0,而判断类型是根据数字前三位判断,
而object判断依据是前三位为0,所以null的类型也会是object
而object判断依据是前三位为0,所以null的类型也会是object
A instanceof B
判断B是否在A的原型链上
constructor
null,undefined没有构造函数
constructor可以被改写
A.isPrototypeOf(B)
A是否在B的原型链上,等同于instanceof
Object.prototype.toString.call(A)
'[object Array]'
'[object Date]'
'[object Object]'
'[object Function]'
···
Symbol.toStringTag()
等比较
undefined === void 0(void number)
数据类型转换
转换规则
NaN和谁都不相等,包括自己
typeof NaN == 'number' //true
NaN !== NaN //true
NaN不能被删除
{configurable:false,
enumerable:false,
value:NaN,
writable:false}
enumerable:false,
value:NaN,
writable:false}
window.isNaN(A)
该方法会将A转换为数字,若不能成功转换,返回true。可以转换返回false
isNaN('1') //false
isNaN(NaN) //true
isNaN('blue') //true
Number.isNaN(A)
判断A是否是数字并且为NaN,则返回true,否则返回false
Number.isNaN(NaN) //true
Number.isNaN('1') //false
Number.isNaN('blue') //false
Object.is(NaN, NaN) == true
严格判断相等
Object.is(+0, -0) //false
数组中的NaN判断
[NaN].indexOf(NaN) === -1 //true
内部调用number::equal机制,有NaN就返回false
[NaN].includes(NaN) === true //true
内部调用number::sameValueZero,左右两边都有NaN返回true
null,undefined两者相等
null == undefined //true
布尔值与其他类型相比较,布尔值会转换为数字
'0' == false => '0' == 0 //true
数字与字符串类型比较,字符串会转为数字
'0' == 0 => 0 == 0 //true
对象和原始类型比较,对象会转为原始类型
({}) == '[object Object]' //true
对象与对象比较,比较的是引用地址
{} == {} //false
条件判断转换为布尔值false的有
""
+0, -0
NaN
null
undefined
对象转换为原始数据类型
优先级
1.[Symbol.toPrimitive]()
2.valueOf()
3.toString()
[] + {} == '' + {} == '[object Object]' //true
2.运算符
一元运算符
+
特殊值
+ {} = NaN
+ undefined = NaN
+ 'str' = NaN
运用
字符串转换数字
+ '1' === 1 //true
!
二元运算符
||
&&
位运算符
&
判断奇偶数
A & 1 == 1 //true,则A为奇数
A & 1 == 0 //true,则A为偶数
|
取整
1.6 | 0 == 1 //true
^
相同为0,相异为1。
无中间变量交换数据
let a = 1, b = 2
a ^= b
b ^= a
a ^=b
// a=2, b=1
a ^= b
b ^= a
a ^=b
// a=2, b=1
~
取整
~x = -Math.floor(x + 1)
~~1.6 === 1 //true
有符号位>>
取整(32位二进制进行计算)
2.9 >> 0 === 2 //true
无符号位>>>
Number.MAX_SAFE_INTEGER >> 0 //-1
Number.MAX_SAFE_INTEGER >>> 0 //4294967295
3.对象
属性描述符
Object.defineProperty(target, name, descriptor)
configurable
是否可配置,可删除
enumerable
是否可枚举,遍历
writable
是否可以被改写
value
当前属性值
新创建的属性,若是没有设置描述符,默认为false。
已存在的属性,若是没有设置描述符,默认为true。
已存在的属性,若是没有设置描述符,默认为true。
相关方法
对象是否可扩展
Object.precentExtensions(obj)
对象obj上不能添加新的属性
Object.isExtensible(obj)
返回布尔值,判断对象是否可扩展
不能新增,可删除,可修改
对象是否封闭
Object.seal(obj)
阻止添加新属性,并将所有现有属性标记为不可配置,
当前属性的值只要是可写的就可以改变。
当前属性的值只要是可写的就可以改变。
Object.isSealed(obj)
返回布尔值,判断对象是否被密封
不能新增,不能删除,可修改
对象是否冻结
Object.freeze(obj)
阻止添加新属性,不可配置,不能修改值
Object.isFrozen(obj)
返回布尔值,判断对象是否被冻结
不能新增,不可删除,不能修改
对象属性遍历
for-in循环
遍历可枚举属性和原型属性
Object.keys()
遍历可枚举属性
Object.hasOwnPropertyNames()
遍历可枚举和不可枚举属性
Object.hasOwnPropertySymbols()
遍历可枚举的symbol属性和不可枚举的symbol属性
Reflect.ownKeys()
遍历可枚举属性,不可枚举属性,symbol属性
proxy
vue2/vue3相关面试题
访问原型
原型
继承
原型链继承
缺点
共享原型属性
借用构造函数继承
缺点
必须在构造函数中定义方法,函数不能重用
子类不能访问父类原型上定义的方法
组合继承(原型链+借用构造函数)
缺点
两次调用父类构造函数
继承父类方法
子类中调用
原型式继承
Object.create()实现
寄生式继承
Object() + 添加属性方法
缺点
给对象添加函数,会导致函数难以重用
组合寄生式继承
Object + 原型链副本拷贝 + prototype修正
只调用一次构造函数
原型链
对象克隆
浅拷贝
slice
concat
扩展运算符
Object.assign
for-in循环
深拷贝
JSON.parse(JSON.stringify(obj))
限制
只能拷贝普通键,Symbol属性不行
NaN, Infinity, null都会返回null
Function, Date, RegExp, Blob等类型不能复制,返回空对象
存在循环引用问题
JSON.parse(str: string, function(key, value){})
在转换解析过程中,可以根据key值来过滤不需要的属性
JSON.stringify(obj:object, replacer: Array | Function), space
replacer若是数组,则只有包含在数组中的属性才会被序列化,
其他属性会被过滤
其他属性会被过滤
replacer若是函数,则同样可以根据key,value对属性处理
space为美化输出格式
为数字则表示空格数,上限为10
为字符串,则字符串当做空格功能使用
为null,则没有空格
任意的函数,symbol值,undefined作为对象的属性值时会被忽略(非数组对象属性值中)
或者是转换为null(出现在数组中)
或者是转换为null(出现在数组中)
函数,undefined 被单独转换时,会返回undefined
NaN, Infinity,null都会被当做null
手写拷贝
普通拷贝
循环引用拷贝
WeakMap
弱引用关联,没有对键的引用,值自动会被GC
垃圾回收相关
4.数组
类数组
常见类数组
arguments
DOM相关(NodeList,HTMLCollection,DOMTokenList等)
类数组转数组
slice
concat
Array.from
数组空元素
稀疏数组判断
内部实现是否有用hasOwnProperty对元素进行处理,
没有处理的空元素会被当做undefined进行值比较
没有处理的空元素会被当做undefined进行值比较
遍历当做undefined不跳过的方法
find
findIndex
findLast
findLastIndex
includes
遍历当做空值跳过的方法
除了上面的方法,其他数组方法都跳过
数组手写
手写数组方法
应用
数据生成器
Array.from(arrayLike, mapFn)
数组去重
forEach + indexOf
filter
set
forEach + 对象属性标记
交集,差集
两数组遍历转换为对象属性查找
基本类型求值
引用类型求值
5.Function
箭头函数
箭头函数不会创建自己的this, 它没有自己的this,只会从自己的作用域链的上一层继承this
因为没有prototype,所以箭头函数不能作为构造函数使用
箭头函数的函数体只有一句代码,返回某个变量可以省去函数体的大括号
立即执行函数
创建一个独立的作用域
可实现私有变量,在IIFE中返回一个函数(也是闭包)
函数内部
arguments
8.this
this指向
严格模式
指向undefined
非严格模式
默认指向全局对象
this的绑定规则完全取决于this的调用位置
new绑定
执行过程
1.创建一个空对象
2.设置空对象的原型
3.执行构造函数,把相关的属性和方法添加到对象上(改变this指向到空对象上)
4.返回对象,如果都早函数返回的是对象类型,就直接返回该对象,否则返回创建的空对象
箭头函数
箭头函数中的this指向定义时的上下文
var name = 'global'
const person = {
name: 'person',
getName: () => {
return this.name
}
}
console.log(person.getName()) //"global"
const person = {
name: 'person',
getName: () => {
return this.name
}
}
console.log(person.getName()) //"global"
var name = "global"
const person = {
name: 'person',
getName: () => {
var s = () => console.log(this.name)
return s
}
}
var getName = person.getName()
console.log(getName()) //"person"
var obj = {name: "obj"}
getName.call(obj) // "person"
const person = {
name: 'person',
getName: () => {
var s = () => console.log(this.name)
return s
}
}
var getName = person.getName()
console.log(getName()) //"person"
var obj = {name: "obj"}
getName.call(obj) // "person"
隐式绑定
隐式绑定的函数会丢失绑定对象
var name = "global"
fucntion foo(){console.log(this.name)}
var obj = {name: "obj", foo: foo}
var bar = obj.foo
bar() // "global"
fucntion foo(){console.log(this.name)}
var obj = {name: "obj", foo: foo}
var bar = obj.foo
bar() // "global"
虽然bar是obj.foo的一个引用,但实际上引用的是foo函数本身,因此bar是直接调用函数
对象属性引用链中只有上一层或者最后一层在调用中起作用
function foo(){console.log(this.name)}
var obj2 = {name:"obj2", foo}
var obj2 = {name: "obj", obj2}
obj1.obj2.foo() // "obj2"
var obj2 = {name:"obj2", foo}
var obj2 = {name: "obj", obj2}
obj1.obj2.foo() // "obj2"
内置的回调函数
setTimeout,setInterval
显示绑定
call
apply
bind
绑定之后不能再修改this指向
new.target
ES6中函数可以作为构造函数实例化一个新对象,也可以作为普通函数被调用。
检测函数是否使用了new关键字调用函数。如果函数是正常调用的,则new.target的值为undefined。
如果是使用new关键字调用的,则new.target将引用被调用的构造函数。
如果是使用new关键字调用的,则new.target将引用被调用的构造函数。
动态解析和执行函数
new Function(arg1, arg2, ..., fnBody)
6.执行上下文与作用域
执行上下文
全局执行上下文
函数执行上下文
作用域
全局作用域
函数作用域
立即执行函数IIFE
该函数内部定义的变量外部无法访问,
调用完之后就会被销毁,不存在闭包问题
调用完之后就会被销毁,不存在闭包问题
7.闭包
指嵌套函数中,内层函数引用了外层函数作用域中的变量,
在全局作用域下可以访问函数作用域中的变量,这就是闭包。
在全局作用域下可以访问函数作用域中的变量,这就是闭包。
使用场景
使用函数式变成时,基本上就有了闭包。
缺陷
在函数执行完成后,被闭包引用的变量会被存储在内存中,不会被释放。
若是过度使用闭包也会导致内存泄漏。
若是过度使用闭包也会导致内存泄漏。
垃圾回收
块级作用域
暂时性死区
let, const声明之前使用,会报错
变量提升
var声明的变量可以在声明之前访问不会报错。
函数提升
函数声明会被提升,但是函数表达式不会被提升
当函数声明和变量都会提升时,函数首先被提升,然后才是变量提升。
作用域链
从当前作用域直到全局作用域,查找某变量的链路
10.DOM
Node节点
type类型
Element(nodeType = 1)
Text(nodeType = 3)
Comment(nodeType = 8)
Document(nodeType = 9)
DocumentType(nodeType = 10)
DocumentFragment(nodeType = 11)
创建节点
使用new方式创建
new Text('text')
document.createXXX方式
document.createTextNode()
document.createElement()
删除节点
Element.remove()
将对象从DOM树中删除
innerHTML | outerHTML
innerHTML
设置或获取HTML表示的元素的后代
outerHTML
获取元素(包括其后代)的序列化HTML片段
修改来达到删除或者替换效果
Document.adoptNode(externalNode)
从其他文档获取一个节点(及其子节点)插入到当前文档(可以iframe形式获取),并从源文档中将该节点删除
可以理解为节点转移
克隆节点
Node.cloneNode(isDeep:boolean = true)
返回该方法节点的一个副本
默认为true, 表示深拷贝(克隆当前节点及其子节点)
false表示只克隆当前节点。
Document.importNode(externalNode, deep = false)
将外部文档的一个节点拷贝一份插入到当前文档,并不会从原文档中删除
默认为false,浅拷贝。true表示深拷贝
Document.adoptNode(externalNode)
Node节点关系
Node & Element
Node常见属性方法
firstChild, lastChild
appendChild
insertBefore
replaceChild
textContent
Element常见属性方法
afer
before
append
prepend
replaceChildren
节点查询
实时更新方法
getElementsByClassName
getElementsByName
getElementsByTagName
MutationObserver
let observer = new MutationObserver((mutationRecord) => {
// 保留属性原来的值
console.log("mutationRecord:", mutationRecord.map(x => x.oldValue))
})
// 过滤没有添加的属性
observer.observe(document.body, {attributeFilter: ['foo']})
document.body.setAttribute('foo', 'bar')
document.body.setAttribute('foo', 'baz')
document.body.setAttribute('foo', 'qux')
document.body.setAttribute('baz', 'qux')
// 每次变化都保留上一次的值
// [null, 'bar', 'baz']
// 保留属性原来的值
console.log("mutationRecord:", mutationRecord.map(x => x.oldValue))
})
// 过滤没有添加的属性
observer.observe(document.body, {attributeFilter: ['foo']})
document.body.setAttribute('foo', 'bar')
document.body.setAttribute('foo', 'baz')
document.body.setAttribute('foo', 'qux')
document.body.setAttribute('baz', 'qux')
// 每次变化都保留上一次的值
// [null, 'bar', 'baz']
DOM事件
DOM0事件
直接在节点上添加"onXXX"事件
DOM2事件
事件处理流程
捕获阶段
从根节点向下传播到目标节点的过程
目标阶段
冒泡阶段
从目标节点向上传播到根节点的过程
默认是冒泡阶段
event事件
preventDefault()
阻止默认的行为,比如href的a标签,checkbox选中不生效等
stopPropagation()
阻止捕获和冒泡阶段中当前事件的进一步传播
stopImmediatePropagation()
阻止同一节点上的其他监听器被调用。比如一个按钮添加了三个事件,
第二个事件调用该方法,后面的事件都不会被触发(第三个事件和冒泡阶段事件都不触发)
第二个事件调用该方法,后面的事件都不会被触发(第三个事件和冒泡阶段事件都不触发)
target和currentTarget区别
target表示触发事件的元素。(谁触发的)
currentTarget表示事件绑定的元素。(谁添加的事件监听函数)
事件注册:addEventListener(type, listener,
useCapture:boolean | options: object)
useCapture:boolean | options: object)
userCapture默认是false,表示为冒泡事件
options
{once: true}
表示该事件只触发一次
{passive: true}
表示不调用阻止默认事件preventDefault
{capture: true}
表示捕获阶段触发该事件
{signal: true}
AbortController的abort()方法调用时,监听器会被移除
let controller = new AbortController()
let signal = controller.signal
btn.addEventListener("click", (e) => {
console.log("click btn")
controller.abort()
}, {
signal
})
// 点击第一次 打印"click btn"
// 事件监听被取消
// 第二次点击不会被响应
let signal = controller.signal
btn.addEventListener("click", (e) => {
console.log("click btn")
controller.abort()
}, {
signal
})
// 点击第一次 打印"click btn"
// 事件监听被取消
// 第二次点击不会被响应
事件删除:removeEventListener
事件委托
利用事件传播的机制,在同一节点处理所有事件。
react中事件统一处理
优点
动态性好
减少内存消耗
DOM3事件
用户界面事件(UIEvent)
焦点事件(FoucsEvent)
鼠标事件(MouseEvent)
滚轮事件(WheelEvent)
输入事件(InputEvent)
键盘事件(KeyboardEvent)
合成事件(CompositionEvent)
自定义事件
CustomEvent(type:string, eventInit:object)
detail:传给event的参数(event.detail中可获取)
<div id="step1">流程1</div>
<div id="step2">流程2</div>
function dispatchEE(target, type, data){
let event = new CustomEvent(type, {detail: data})
target.dispatchEvent(event)
}
btn.addEventListener("click", function(){
setTimeout(() => {
dispatchEE(step1, "step-1", {param:"param 1"})
}, 2000)
})
step1.addEventListener("step-1", function(event){
step1.textContent = "流程1" + event.detail.param
setTimeout(() => {
dispatchEE(step2, "step-2", {param:"param 2"})
}, 2000)
})
step2.addEventListener("step-2", function(event){
step1.textContent = "流程2" + event.detail.param
setTimeout(() => {
console.log('complete')
}, 2000)
})
<div id="step2">流程2</div>
function dispatchEE(target, type, data){
let event = new CustomEvent(type, {detail: data})
target.dispatchEvent(event)
}
btn.addEventListener("click", function(){
setTimeout(() => {
dispatchEE(step1, "step-1", {param:"param 1"})
}, 2000)
})
step1.addEventListener("step-1", function(event){
step1.textContent = "流程1" + event.detail.param
setTimeout(() => {
dispatchEE(step2, "step-2", {param:"param 2"})
}, 2000)
})
step2.addEventListener("step-2", function(event){
step1.textContent = "流程2" + event.detail.param
setTimeout(() => {
console.log('complete')
}, 2000)
})
发布订阅
class EventEmitter extends EventTarget {
on = (type, listener, options) => this.addEventListener(type, function wrap(e){
return (listener.__wrap__ = wrap, listener.apply(this, e.detail || []))
}, options || false)
off = (type, listener) => this.removeEventListener(type, listener.__wrap__)
emit = (type, ...args) => this.dispatchEvent(new CustomEvent(type, {detail: args}))
once = (type, listener) => this.on(type, listener, {
once: true,
capture: true
})
}
on = (type, listener, options) => this.addEventListener(type, function wrap(e){
return (listener.__wrap__ = wrap, listener.apply(this, e.detail || []))
}, options || false)
off = (type, listener) => this.removeEventListener(type, listener.__wrap__)
emit = (type, ...args) => this.dispatchEvent(new CustomEvent(type, {detail: args}))
once = (type, listener) => this.on(type, listener, {
once: true,
capture: true
})
}
浏览器DOM渲染相关
11.BOM
location
navigator
浏览器
事件循环
同源策略
垃圾回收
客户端存储
http
资源请求
状态码
请求头、响应头
三次握手
四次挥手
RSA/TLS握手阶段
ECDHE/TLS握手阶段
http2
http3
0 条评论
下一页