预编译
局部预编译
-
生成ao 对象
-
把变量和形参的名字作为oa对象的属性,值是undefind
-
把实参赋值给形参
-
声明函数,如果函数与变量同名,函数的声明会覆盖变量(函数表达式不算)
-
执行代码
(预编译分为全局预编译和局部预编译,全局预编译发生在页面加载完成时执行,而局部预编译发生在函数执行的前一刻。
全局预编译
- 生成go对象
- 把变量当作go对象的属性,值是undefine
- 声明函数,如果函数和变量同名就,函数会覆盖变量
- 执行代码
function test(){
// 这里的b是未经声明的变量,所以是归window所有的。
var a = b = 110;
}
this
- 匿名函数的this 和 setTimeout里面传入的函数的this 指向window
-
函数直接调用则这个时候它指向window(也就是 调用的时候前面没有对象.)
-
函数作为对象的方法进行调用,则这个对象是谁,this就指向谁 (一定要是 对象.方法() 对象点方法且执行了)
-
不用去看这个值是什么,只要看他是不是作为对象的方法
5. 222 111 222 333
-
普通函数的this指向在定义的时候并不能确定,要在执行的时候才能确定。
-
上面第4点的 b.say(a.say ) 这个对话,可以看成是 b的say函数里面 再执行的那个函数,那么 其实就只是在执行 这个高阶函数,这个高阶函数独立形成一个密闭环境,不受外面的b的say函数影响。
-
如果执行的时候前面没有任何对象,则在非严格模式(严格模式下指向undefined)下this指向window。a()----相当于 window.a()
-
如果执行的时候前面有一个对象,则this指向这个对象
-
当函数前面有多个对象的时候,this指向离他最近的一个函数
var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); //12 } } } o.b.fn();
```
var o = {
a:10,
b:{
// a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();
```
6. this永远指向最后调用他的对象
```
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
```
### 构造函数的this
1. 构造函数会改变this的指向,把this指向 新构造出来的对象。
2. 但是如果构造函数return的是一个对象(函数,对象,数组)(不包括null)的话,this指向这个对象。
### 箭头函数的this
-
箭头函数的是没有this的,他的this取决于他所在的那个对象的父作用域。
-
普通函数的this取决于执行时的对象,没有运行的时候是不知道他的this的,而箭头函数的this定义好之后就固化了。怎么也不会改变,用bind,call也无法改变
拷贝
- 因为对于引用数据类型,进行赋值的时候,只能保存了地址。所以都是在操作同一个对象,所以需要用到拷贝。
- 浅拷贝的话就是对于一个对象,只拷贝基础数据类型,对于引用数据类型是直接拷贝地址。
- 深拷贝是对于整个对象,不管属性是基础数据类型还是引用数据类型都会复制,而不是只拷贝地址。
- 赋值的话,是直接拷贝整个对象的地址。
浅拷贝
防抖函数
- 防抖函数是闭包的应用。
- 使用的案例有输入之后,m秒之后自动搜索补全。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dIKtz9ny-1644818469727)(./js高级/截屏2021-08-14 下午2.43.08.png)]
把存储定时器的变量放在一个闭包里面,这样既可以不用污染到全局环境,又可以保存变量。
function aa(del,fun)
{
let timeOut
return function cc()
{
cleantimeout(timeOut)
timeOut= setTimeOut(function(){
fun()
},del)
}
}
let nn=aa(100,function(){})
ww.onclick(nn())
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cqohqKCZ-1644818469729)(./js高级/截屏2021-08-14 下午3.41.18.png)]
节流函数
- 节流函数是用在,一段时间内多次执行点击多次函数,也只会执行一次。防抖函数是执行事件的时候会延时,延时期间再触发事件也无效。
- 就是一段时间内,多次触发只执行一次。
- 节流一段时间内只执行一次,防抖是触发后n秒后执行。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8jFdmKV7-1644818469730)(./js高级/截屏2021-08-16 上午10.21.14.png)]
function aa(del,fun)
{
let timeout=undefind
return function cc (){
if(!timeOut)
{
settimeOut(function(){
fun()
//要记得清理掉
timeout=undefine
},del)
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fyITeeDk-1644818469731)(./js高级/截屏2021-08-14 下午5.02.25.png)]
防抖节流在图片懒加载中的应用
js作用域
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-93YKj8un-1644818469733)(./js高级/截屏2021-08-16 上午10.46.05.png)]
- 函数在他的父级作用域被执行的之前,父级作用域进行预编译的时候就会被定义。定义不会生成oa对象。等到函数自己要执行的时候,才会预编译自己的代码,从而生成oa对象。
- ao是函数在预编译的时候创建的,Go 是全局在预编译的时候创建的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u6MGOnMx-1644818469734)(./js高级/截屏2021-08-16 上午11.01.11.png)]
-
这种false的,虽然最后不会执行代码,但是预编译的时候也会编译这个变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2atAN2Xp-1644818469736)(./js高级/截屏2021-08-16 上午11.06.58.png)]
-
作用域链是我们访问不到的,他是ao们和go的集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bKwOYmKc-1644818469737)(./js高级/截屏2021-08-16 上午11.51.25.png)]
- 对于这段代码,首先一开始执行的时候,会先开始预编译全局的代码,生成go对象,然后定义a函数。这个时候 就能在go中看到 global 和 a函数 。此时作用域上只有go
- 然后 执行代码,去到a() ,开始执行a函数,对a函数先进行预编译 ,生成oa ,oa中有b函数,aa。 定义b函数。这个时候 作用域上就有 go 和 a函数的oa。
- 接着执行a函数里面的代码aa=123,再执行b函数。此时作用域上只有 go 和 a函数的oa。
- 执行b函数的时候,进行预编译,形成b函数oa ,里面有 bb 这个属性,此时,作用域上有go 和a函数的oa,b函数的oa。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ueRgBS9o-1644818469739)(./js高级/截屏2021-08-16 上午11.55.58.png)]
(./js高级/截屏2021-08-16 下午2.33.19.png)]
- 也就是说 a函数执行的时候,对b函数进行定义,所以a函数执行的时候和b函数定义的时候的作用域链是一样的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXjOclnQ-1644818469743)(./js高级/截屏2021-08-16 下午2.37.37.png)]
所以这个闭包中a函数执行完毕之后被销毁,因为b函数被定义的时候 能访问到a函数的ao 所以 后续依旧可以拿到a函数的变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HhHNHUOp-1644818469744)(/Users/apple/Desktop/一些资料/md/js高级/截屏2021-10-08 下午2.48.53.png)]
作用域在函数定义的时候就确定了,普通函数的this 在执行的时候才确定
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6aJlU7Q-1644818469745)(/Users/apple/Desktop/一些资料/md/js高级/截屏2021-10-08 下午2.00.25.png)]
所以这个的答案是2
- 闭包就是一个函数可以访问到另外一个函数的内部变量。
- 比如现在有一个函数a里面包含一个函数b形成闭包。因为在执行a函数的时候会定义b函数,b函数在定义的过程中就能访问得到a函数的oa(执行上下文),所以当a函数执行完毕 销毁之后,b函数还能访问到a函数的变量。
- 闭包的优点:能够避免全局污染;能够保存变量;
- 闭包的缺点:消耗内存,使用不当可能会造成内存泄漏。
事件循环机制
- 事件循环机制由 调用栈 微任务队列 消息队列 组成。
- 调用栈的话,可以理解成在这个地方执行 代码。栈的话,是一个先进后出,比如 a函数中调用b函数,执行a函数的时候,a函数被压入调用栈,然后a中调用了b函数,则b函数也被压入栈,b函数执行完成先弹出,a函数进行执行,执行完毕弹出。
- 每一个宏任务后面都有一些微任务。本次的宏任务执行完之后,就会先执行微任务,再执行下一个宏任务。一个宏任务执行完执行微任务就是一次事件循环。微任务就在微任务队列里面。在执行宏任务的时候,如果里面有微任务就会放在微任务队列里面。
- 如果是在浏览器中会先看看需要更新dom不,如果需要就更新dom 然后再去,消息队列里面拿新的任务来。
- 对于这道题就会先执行then 然后dom再被加入p标签,然后再执行setTimeout
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NDc49DQQ-1644818469747)(./js高级/截屏2021-08-17 上午11.38.43.png)]
- 对于这个的话,首先执行func2(), 先把setTimeOut压入调用栈,然后把setTimeout的 consloe 放在消息队列里面。
- 之后把func1 压入调用栈,执行consloe (1)
- 再执行consle(3)
- 清空了调用栈的东西,又因为微任务队列里面没有东西,再去消息队列里面把console(2)执行了
- 1 3 2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fgpVa1wn-1644818469748)(/Users/apple/Desktop/一些资料/md/js高级/截屏2021-10-08 下午3.12.41.png)]
- 消息队列,对于异步的操作,且是宏任务的,当代码执行到这里的时候,会先把异步的放一边,直到代码可以用了就会放到消息队列中,调用栈中的同步任务执行完毕之后,就会先执行微任务队伍里面的东西,全部做完之后就会去去消息队列里面拿到新的宏任务开始新一轮的事件循环。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Orh65aQN-1644818469749)(./js高级/截屏2021-08-16 下午3.12.55.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8j5Llysr-1644818469752)(./js高级/截屏2021-08-16 下午3.41.08.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sNChSHdG-1644818469754)(./js高级/截屏2021-08-16 下午3.39.56.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ko3yWIbp-1644818469755)(./js高级/截屏2021-08-16 下午3.43.54.png)]
-
宏任务:定时器,fetch。
-
微任务 promise的then,awit,async (promise的 new promise 在then之前全部都是宏任务)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QPPRONed-1644818469756)(./js高级/截屏2021-08-17 上午10.57.02.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KDTBCn99-1644818469758)(./js高级/截屏2021-08-17 上午11.37.09.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EaS1UBpD-1644818469760)(/Users/apple/Desktop/一些资料/md/js高级/截屏2021-08-17 下午3.35.16.png)]
一些题目
-
造成内存泄漏的四种
闭包,被遗忘的定时器,脱离dom的引用 ,意外的全局变量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lulRNt4d-1644818469761)(./js高级/截屏2021-08-19 上午10.45.59.png)]
数组扁平化
-
数组扁平化就是指把多维数组变成一维数组,有可能长这样 【1,2,3,【2,【3.4】,3】,6,8】
-
用自带的方法 arr.flat( 参数 ) 可以填 数字,表示是扁平到第几层,比如 arr.flat(3) ; 如果不知道层数,可以填 infinity arr.flat( infinity )
-
用正则
Json.stringify(arr).replace( / \[ |\] /g ,“” )
---- 这个出来之后是字符串 且没有 【】 -
改进一下
Json.parse("["+ (Json.stringify(Array)).replace(/\[|\]/g,"") +"]")
-
用reduce
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YLdRf31p-1644818469763)(./js高级/截屏2021-08-21 下午3.28.09.png)]
let list =[] function cl(arr) { arr.reduce((pre,cur)=>{ return pre.concat( Array.isArray(cur)?cl(cur):cur ) },[]) }
-
用函数递归
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8C7fzYzt-1644818469764)(./js高级/截屏2021-08-19 下午3.56.57.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3fGKFdW-1644818469765)(./js高级/截屏2021-08-19 下午3.00.57.png)]
reduce
-
return 的东西会作为 下一次 pre的值
-
利用rudece计算元素出现次数
let aa = arr.reduce (function(pre,cur){ if(cur in pre) { pre[cur]++ } else { pre[cur]:1 } return pre }, {})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RgwQrEuP-1644818469766)(./js高级/截屏2021-08-19 下午4.13.50.png)]
Bfc
- 最好的做法是 overflow:hidden
- 取消高度塌陷,要让父元素变成bfc
- 浮动覆盖,要把 被覆盖的变成bfc
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rv5KKAsL-1644818469767)(./js高级/截屏2021-08-19 下午3.26.01.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GBF8LMGE-1644818469768)(./js高级/截屏2021-08-19 下午3.33.28.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qKL9iLPT-1644818469769)(./js高级/截屏2021-08-19 下午3.36.47.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lufYL3IY-1644818469770)(./js高级/截屏2021-08-19 下午3.37.08.png)]
数组相关
-
把类数组转化成 数组 (因为ie8以下不能用slice 所以放在try catch里面)
let arr= [] function toArr(list) { try{ arr= Array.prototype.slice.call(list) }catch(e) { for(let i=0; i<list.length;i++ ) { arr[arr.length]=list[i] } } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W6M9N7k3-1644818469771)(./js高级/截屏2021-08-21 下午3.25.13.png)]
-
数组合在原来的数组里面不生成新数组
- concat 这个方法参数可以是多个,可以是元素,也可以是数组,但是会生成新的数组
- push的话,可以传入多个,但只能是元素,不能传入数组
Array.prototype.push.apply (arr1,arr2 )
- 这个话,利用apply传入一个数组 arr2,然后利用push 放到arr1里面
-
判断数据类型
利用 Objcet.prototype.toString.call ( )
let myType={ '[object Object]':"obj", "[object Array]": "arr", "[object String]":"str" } function isType(item) { let aa =Object.prototype.toString.call(item) return myType[aa] || [] }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b2tQUOtt-1644818469772)(./js高级/截屏2021-08-21 下午3.40.17.png)]
原型
-
构造函数有一个属性叫prototype
-
原型就是 prototype 是一个对象
-
–proto-- 是原型链的一个点 ,是一个属性,指向 他所在的对象的构造函数的prototype,对象都有该属性
-
又因为prototype是一个对象,所以他也有–proto–属性
-
原型链的尽头是Object的Prototype,它的–proto–指向null
-
因为有原型链,所以一个对象上,以 obj.属性 这种方式找不到 某个属性或者方法的时候就会顺着原型链去找,直到找到 object ,找到就返回,找不到就没戏了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nnso4MBs-1644818469773)(./js高级/截屏2021-08-21 下午4.31.32.png)]
js 技巧
-
判断传入的参数有没有某个值
-
把那些目标值写成一个数组,然后通过includes,或者indexof 去判断
function aa (item) { let list = ["dog","cat"] if(list.includes(item)) { console.log(item) } }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4rwoMPTR-1644818469774)(./js高级/截屏2021-08-21 下午4.31.32.png)]
-
-
提前退出 判断一个对象有没有某些要的属性,没有就返回,有就输出
老方法是用if else 一个个判断[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PIpMZkg0-1644818469775)(./js高级/截屏2021-08-23 上午10.18.37.png)]
新方法是用结构赋值,然后进行判断,然后还有就是结构赋值的话,最好加上默认值是{}
function aa ({name,age}={}) { if(!name) { return "no name" } if(!age) { return "no age" } return "名字叫"+name + "年龄"+age } aa({name:'aa',age:12})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DzEAewr5-1644818469776)(./js高级/截屏2021-08-23 上午10.21.09.png)]
-
根据输入的东西返回某个值,比如根据颜色打印水果
-
一般会用switch 去判断
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JGwK1Ouo-1644818469776)(./js高级/截屏2021-08-23 上午10.27.13.png)]
-
-
但是可以用 对象的这种形式去改写 就快很多
let ff ={ yellow:ban, red:apply } function aa (item) { //短路表达式,如果没有东西就返回空 consloe.log(ff[item]||{}) }
-
对于es5的话,定义对象的时候key会被自动调用 toString转化成字符串,从而导致不能用对象作为key
比如这个 用对象做key,然后 这两个对象会被用toString 转化成 【object Object】,所以最后就只有一个属性,且属性值是22
然后es6 就有 map 就是对象。然后key可以用对象。可以连续调用