继承
主要分为
- 原型链继承
- 构造函数继承
- 组合继承
- 原型式继承
- 寄生式继承
- 寄生组合式继承 这里进行较为详细的阐述及举例
事件流
JS的DOM事件流
DOM里面触发事件的流程,目标,冒泡,捕获三个阶段
事件代理
就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素
事件委托
描述:把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素
执行机制:当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数
优点:
- 减少整个页面所需的内存,提升整体性能
- 动态绑定,减少重复工作
缺点:如果把所有事件都用事件代理,可能会出现事件误判,即本不该被触发的事件被绑定上了事件
局限性:
focus、blur这些事件没有事件冒泡机制,所以无法进行委托绑定事件mousemove、mouseout这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的
函数
可以使用哪两种声明方式声明函数
区分
let test=function(){} //函数表达式
(function(){})() //函数表达式
setTimeout(function(){},1000) //函数表达式
function text(){} //函数声明
不同处
| 特征 | 函数声明 | 函数表达式 | | -- | ---- | ----- | | | 预提升 | 会进行预提升 | 不会进行预提升 | | 访问范围 | 函数内部和函数父级作用域 | 函数内部 | | 函数名 | 不能没有 | 可以没有 |
Arguments是什么
是函数实参的集合,是一个伪数组。箭头函数没有arguments,箭头函数是用rest操作符(...)获取箭头函数所有实参的集合。
注:伪数组有类似数组特性,如具有length属性,按索引方式存储数据;但是不能使用数组方法,可使用Array.from(),Array.prototype.slice.call(),展开运算符等方法将伪数组转为数组
new执行流程
- 创建一个空对象
- 将对象与构建函数通过原型链连接起来
- 将构建函数中的
this指向新建的空对象 - 执行构造函数内部代码
- 根据构建函数返回类型作判断,如果是简单数据类型(string,number,boolean,undefined,null)则返回实例,如果是复杂数据类型的对象则返回对象
数组
数组方法
按类型区分
数组循环类方法:forEach map filter every some fill findIndex find reduce
数组拼接类方法:slice splice split push pop unshift shift concat join reserve sort
按是否改变原数组区分
原数组改变的方法有:splice split push pop unshift shift reverse sort
不改变原数组的方法有:forEach map filter every some fill findIndex find reduce slice concat join indexOf forEach 数组循环类及部分拼接类方法及去重
字符串方法:
增
- concat():用于将一个或多个字符串拼接成一个新字符串
删:返回调用它们的字符串的一个子字符串,而且都接收一或两个参数
- slice()
- substr()
- substring() 改:创建字符串的一个副本,再进行操作
- trim()、trimLeft()、trimRight():删除前、后或前后所有空格符,再返回新的字符串
- repeat():接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果
- padStart()、padEnd():复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
- toLowerCase()、 toUpperCase():大小写转化 查:
- chatAt():返回给定索引位置的字符,由传给方法的整数参数指定
- indexOf():从字符串开头去搜索传入的字符串,并返回位置(如果没找到,则返回 -1 )
- startWith():从字符串中搜索传入的字符串,并返回一个表示是否包含的布尔值
- includes() 拆分字符串:
- split():把字符串按照指定的分割符,拆分成数组中的每一项 针对正则表达式的方法:
- match():接收一个参数,可以是一个正则表达式字符串,也可以是一个
RegExp对象,返回数组 - search():接收一个参数,可以是一个正则表达式字符串,也可以是一个
RegExp对象,找到则返回匹配索引,否则返回 -1 - replace():接收两个参数,第一个参数为匹配的内容,第二个参数为替换的元素(可用函数)
对象
js内置对象
Math、 Date 、Array、String等
this
this是什么
this是当前执行上下文(global、function 或 eval)的一个属性
this的指向
-
在方法中,
this指的是所有者对象。 -
单独的情况下,
this指的是全局对象。 -
在函数中,
this指的是全局对象。 -
在函数中,严格模式下,
this是undefined。 -
在事件中,
this指的是接收事件的元素。 -
使用
call,apply,bind改变this指向 。
JS中改变this指向的上下文调用的三种方法
call,apply,bind
参数
函数名.call(修改this,形参1,形参2...)
函数名.apply(修改this, 数组/伪数组 )
函数名.bind(修改this)
区别
传参方式不同 : call是逐一传参, apply是数组/伪数组 传参方式不同
执行机制不同 : call和apply立即执行函数, bind不会立即执行函数
call和apply用一次,改一次
bind修改一次,永久有效
数据类型
如何检测数据类型
1.typeof 数据: 检测数据类型
注:有两种数据类型无法检测 : null 和 array
-
万能数据类型检测 :
Object.prototype.toString.call( 数据 ) -
object instanceof constructor:instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上注:可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型。返回布尔值
JS中的数据类型
基本类型
NumberStringBooleanUndefinednullsymbolBigInt
null和undefined区别
undefined在和null进行==比较时两者相等,全等于比较时两者不等
null表示没有对象,null 值表示指针指向一个空对象,经常用作函数的参数,或作为原型链的顶级对象。
undefined表示缺少值,没有指针
null+1和undefined+1的值
null+1=1
undefined+1=NaN+1=NaN
谈一谈symbol
Symbol (符号)是原始值,且符号实例是唯一、不可变的。符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险
使用方式let genericSymbol = Symbol()
谈一谈BigInt
用途:精确查询数字类型及多种数字类型转换
使用方法
- 在整数的末尾追加n
- BigInt()
复杂类型
ObjectArrayFunction
JS类型转换机制
- 强制转换(显示转换)
- Number(),parseInt(),parseFloat()
- String(),toString()
- Boolean()
- 自动转换(隐式转换)
- 比较运算(
==、!=、>、<)、if、while需要布尔值地方 - 算术运算(
+、-、*、/、%)
- 比较运算(
==和===
- ==:
JavaScript中存在隐式转换。等于操作符(==)在比较中会先进行类型转换,再确定操作数是否相等 - ===:操作符(===)只有两个操作数在不转换的前提下相等才返回
true。即类型相同,值也需相同
null==undefined为true
null===undefined为false
Promise
状态
promise对象仅有三种状态
pending(等待态)fulfilled(成功态)rejected(失败态)
简单描述
是ES6新增的一个特性,用的时候一般要new一下,做为一个构造函数来使用,里面有一些参数,成功时resolve 会触发.Then,失败时reject会触发.catch,主要解决的是回调地狱的问题,不过一般使用的时候呢不会直接是用promise,她虽然能解决回调地狱 但是不能简化代码,使用promise会使代码变得复杂,所以就需要结合async await来配合promise使用,这样既能解决回调地狱,又能简化代码。
流程
方法
- all()
- race()
- allSettled()
- resolve()
- reject()
- try()
Promise.all()
Promise.all()方法用数组将多个 Promise实例包装成一个新的 Promise实例,数组中若有一个实例为失败态,Promise.all()则直接返回该失败态
深拷贝和浅拷贝
浅拷贝和深拷贝如何实现
浅拷贝
Object.assignArray.prototype.slice(),Array.prototype.concat()- 使用...拓展运算符
深拷贝
- _.cloneDeep():lodash库的方法,_为所有方法
- jQuery.extend():通过$使用Jquery的方法
- JSON.stringify():JSON.parse(JSON.stringify(obj))
- 手写循环递归
深拷贝和浅拷贝的区别
- 浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
- 深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址
闭包
什么是闭包
闭包是指有权访问另一个函数作用域中变量的函数
闭包作用
- 创建私有变量
- 延长变量的生命周期
闭包使用场景
- 使用回调函数
- 使用函数作为参数
- 自执行函数
- 防抖节流
- 循环赋值
- return回一个函数
闭包的缺陷
闭包会减缓处理速度和提高内存消耗,容易导致内存泄漏
JS事件循环
JS单线程
在 JavaScript 中我们听到最多的词可能就是所谓的“单线程”,所以导致了在 JS 中所谓的异步并行模型和许多后台语言是不同的。简而言之,虽然 JavaScript 是在单线程中去执行所有的操作,但它会基于事件循环(EventLoop)的过程去实现所谓的“异步”,从而给我们造成多线程的感觉。
Event Loop
在JavaScript中,任务被分为两种,一种宏任务(MacroTask)也叫Task,一种叫微任务(MicroTask)
宏任务
script全部代码、setTimeout、setInterval、setImmediate。
微任务
Process.nextTick(Node独有)、Promise
浏览器中的Event Loop
Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。
JS调用栈
JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。
同步任务和异步任务
Javascript单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
作用域链
什么是作用域链
作用域,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合
换句话说,作用域决定了代码区块中变量和其他资源的可见性
作用域链都包括什么
我们一般将作用域分成:
- 全局作用域:任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问
- 函数作用域:函数作用域也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问
- 块级作用域:ES6引入了
let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号之外不能访问这些变量
JS原型,原型链
什么是原型
doSomething.prototype 就是原型,它是一个对象,我们也称它为原型对象。,每个对象拥有一个原型对象
什么是原型链
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种逐级查找的过程被称为原型链
ajax
是什么
AJAX全称(Async Javascript and XML)
即异步的JavaScript 和XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页
Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面
实现过程
- 创建
Ajax的核心对象XMLHttpRequest对象 - 通过
XMLHttpRequest对象的open()方法与服务端建立连接 - 构建请求所需的数据内容,并通过
XMLHttpRequest对象的send()方法发送给服务器端 - 通过
XMLHttpRequest对象提供的onreadystatechange事件监听服务器端你的通信状态 - 接受并处理服务端向客户端响应的数据结果
- 将处理结果更新到
HTML页面中
JS本地存储方式
方式
javaScript本地缓存的方法我们主要讲述以下三种:
cookiesessionStoragelocalStorageindexedDB(了解)
indexedDB(了解)
indexedDB是一种低级API,用于客户端存储大量结构化数据(包括, 文件/ blobs)。该API使用索引来实现对该数据的高性能搜索
虽然 Web Storage对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太有用。IndexedDB提供了一个解决方案
优点:
- 储存量理论上没有上限
- 所有操作都是异步的,相比
LocalStorage同步操作性能更高,尤其是数据量较大时 - 原生支持储存
JS的对象 - 是个正经的数据库,意味着数据库能干的事它都能干
缺点:
- 操作非常繁琐
- 本身有一定门槛
关于indexedDB的使用基本使用步骤如下:
- 打开数据库并且开始一个事务
- 创建一个
object store - 构建一个请求来执行一些数据库操作,像增加或提取数据等。
- 通过监听正确类型的
DOM事件以等待操作完成。 - 在操作结果上进行一些操作(可以在
request对象中找到)
关于使用indexedDB的使用会比较繁琐,大家可以通过使用Godb.js库进行缓存,最大化的降低操作难度
区别
关于cookie、sessionStorage(会话缓存)、localStorage三者的区别主要如下:
- 存储大小:
cookie数据大小不能超过4k,sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大 - 有效时间:
localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭 - 数据与服务器之间的交互方式,
cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端;sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
应用场景
在了解了上述的前端的缓存方式后,我们可以看看针对不对场景的使用选择:
- 标记用户与跟踪用户行为的情况,推荐使用
cookie - 适合长期保存在本地的数据(令牌),推荐使用
localStorage - 敏感账号一次性登录,推荐使用
sessionStorage - 存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用
indexedDB
强缓存和协商缓存
检测缓存是否过期若没过期则直接使用缓存(强缓存),若过期则需要发送http请求(协商缓存)
防抖和节流
目的:
优化高频率执行代码,减少指定事件调用频率
防抖:
描述:触发事件后指定时间后才执行函数,如果在指定时间内又触发了事件,则会重新计算函数执行时间(执行最后一次函数)
使用场景:
- 搜索框输入功能。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小
resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
节流:
描述:触发事件后指定时间后才执行函数,若连续触发事件但是在指定时间内只执行一次函数。(执行第一个函数)
使用场景:
- 滚动加载,加载更多或滚到底部监听
- 搜索框搜索功能