前端必会知识

1.闭包(Closure)

概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域

闭包的注意点:

  • 闭包不一定有return。什么时候用到return?外部如果想要使用闭包的变量,此时则需要return
  • 闭包一定会有内存泄漏吗
js关于return的使用 复制代码
//普通形式  统计调用次数
let i = 0
function fn() {
i++
console.log(`函数被调用了${i}次`)
}

//闭包形式  统计调用次数  实现数据私有,此时i作为局部变量,无法直接修改i的值
function count(){
let i = 0
function fn() {
i++
console.log(`函数被调用了${i}次`)
 }
 return fn
}
const fun = count()

使用闭包的作用:使用数据的私有

js内存泄漏 复制代码
function fn(){
let count =1
function fun() {
count++
console.log(`函数被调用了${count}次`)
 }
 return fun
}
const result = fn()
result()  //2
result() //3

什么存在内存泄漏? count变量 借助JS垃圾回收机制的标记清除法可以看到:

  1. result是一个全局变量,代码执行完毕不会立即销毁
  2. result使用fn函数
  3. fn用到fun函数
  4. fun函数里面用到count
  5. count被引用就不会被回收,所以一直存在
  6. 此时,闭包引起了内存泄漏

注意:不是所有的内存泄漏都要手动回收result=null,比如react里很多闭包不能回收

2.事件循环(eventloop)

  1. js是单线程,防止代码阻塞,我们把代码任务分为:同步、异步
  2. 同步代码给js引擎执行,异步代码交给宿主环境(比如浏览器)
  3. 同步代码放入执行栈中,异步代码等待时机成熟推入任务队列排队
  4. 执行栈执行完毕,会去任务队列看是否有异步任务,有就送到执行栈执行,反复循环查看执行,这个过程称为事件循环

3.宏任务、微任务

js把异步任务分为宏任务和微任务

宏任务是由宿主(浏览器、Node)发起 在浏览器中:

  • script(代码块)
  • 事件
  • 网络请求(Ajax/Fetch)
  • setTimeout()一次性定时器/setInterval()定时器

微任务是由Js引擎发起的任务,

  1. Promise。Promise本身同步,then/catch的回调函数是异步的
  2. process.nextTick
  3. Async/Await
  4. object.observe等等

执行顺序:先微任务再宏任务

4.节流跟防抖

防抖:

指连续触发事件但是在设定的一段时间内中只执行最后一次 例如:设定1000毫秒执行,当你触发事件了,他会1000毫秒后执行,但是在还剩500毫秒时又触发了,那就会重新开始1000毫秒之后再执行

应用场景:

  • 搜索框搜索输入
  • 文本编辑器实时保存

代码实现思路?利用定时器,每次触发前先清掉以前的定时器

js 复制代码
let timerId = null
document.querySelector('.ipt').onkeyup = function(){
//防抖
if(timerId !==null) {
clearTimeout(timerId)
}
timerId = setTimeout(() =>{
console.log("我是防抖")
},1000) 
}

节流:

指连续触发事件但是在设定的一段时间内中只执行一次函数。 例如:设定1000毫秒执行,那你在这1000毫秒内触发多次,也只是在这个1000毫秒后执行一次

应用场景:

  • 高频事件,例如快速点击、鼠标滑动、resize事件、scroll事件
  • 下拉加载
  • 视频播放记录时间等

实现思路:利用定时器,等待定时器执行完毕,才重新开始定时器

js 复制代码
let timerId = null
document.querySelector('.ipt').onmouseover = function(){
//节流
if(timerId !==null) {
return
}
timerId = setTimeout(() =>{
console.log("我是节流")
timerId = null
},100) 
}

lodash库,利用里面的debounce(防抖)和throttle(节流)来实现

5.原型跟原型链

原型:

每个函数都有prototype属性,称之为原型。因为这个属性的值是个对象,也称之为原型对象。

作用:

  1. 存放一些属性跟方法
  2. 在js中实现继承

__proto__:每个对象都有这个属性。这个属性指向它的原型对象

js 复制代码
const arr = new Array(1,2,3)
arr.reverse()
console.log(arr.__proto__ === Array.prototype) //true

原型链:

对象都有__proto__属性,这个属性指向它的原型对象,原型对象也是对象,也有__proto__属性,指向原型对象的原型对象,这样一层一层形成的链式结构称之为原型链,最顶层找不到则返回null

对象如何找属性|方法: 先在对象本身找=>构造函数中找=>对象原型中找=>构造函数原型中找=>对象上一层原型中查找

6.作用域

注意:

  • 除了函数外,js是没有块级作用域
  • 作用域链:内部可以访问外部的变量,但是外部不能访问内部的任何变量。如果内部有,优先查找内部,没有再找外部
  • 注意声明变量是用var还是没有写(默认就是window.)
  • 注意:js有变量提升的机制(变量悬挂声明)
  • 优先级:声明变量>声明普通函数>参数>变量提升
js 复制代码
function c (){
 var b =1;
 function a(){
  console.log(b) //undefined  因为内部有 
  var b=2
  console.log(b) //2
 }
 a();
 console.log(b) //1
}
c();

//如果在函数a中,没有声明 var b=2,那么打印出来的全是1
//注意:本层作用域有没有此变量,谨防变量提升
js 复制代码
var name = "a"
(function(){
//此时name在这个作用域内有,所以变量悬挂
  if(typeof name == 'undefined'){
     var name = 'b'
     console.log("111"+name)
     }else{
       console.log("222"+name);
       }
 })()
 
 最终打印:111b
js 复制代码
function fun(){
console.log(a) //function a(){}
var a = 2;
function a(){}
}
fun()

//注意:普通声明函数是不看写函数的顺序

//如果只写以下形式没有括号
console.log(fun); //那么打印的就是这个函数体

//如果写new
console.log( new fun()); //那么打印就是一个对象,并且会执行函数体内代码
js作用域+this指向+原型考题一 复制代码
function Foo(){
 getName = function(){console.log(1)}  //这个是全局变量 window.
 return this; //普通函数this指向window
}
Foo.getName = function(){console.log(2)}
Foo.prototype.getName = funtion(){console.log(3)}
var getName = function(){console.log(4)}
function getName(){
 console.log(5)
}

Foo.getName(); //2
getName();     //4 
Foo().getName();  //1 因为Foo() 则函数调用,相当于window.getName()
getName();       //1  因为后者覆盖了前者
new Foo().getName(); //3
js作用域+this指向+原型考题二 复制代码
var o = {
   a:10,
   b:{
       fn:function(){
            console.log(this.a);
            console.log(this);
       }
   }
}

o.b.fn(); //这个this指向的是o.b这个对象
//打印出来
//undefined   因为o.b这个对象并没有a这个变量
//{fn:f}   打印b对象


window.name = 'xxx';
function A(){
  this.name = 123;
}
A.prototype.getA = function(){
    console.log(this);
    return this.name +1;
}

let a = new A()
let funcA = a.getA;
funcA() //这里的this代表window
相关推荐
北京_宏哥10 分钟前
《刚刚问世》系列初窥篇-Java+Playwright自动化测试-30- 操作单选和多选按钮 - 番外篇(详细教程)
java·前端·测试
leslie040310 分钟前
从零构建微前端生态平台:基于 Module Federation 的最佳实践
前端
筷子夹豆腐11 分钟前
Vue3 解决大屏自适应(缩放)解决方案
前端
Qinana11 分钟前
🚀 用代码搭建「心情小窝」:一个极简情绪记录工具的实现 📝
前端·javascript
可乐202712 分钟前
为什么监听数据变化 页面才会出现内容
前端
isixe13 分钟前
uniapp 兼容 H5 滚动
前端·vue.js
JarvanMo13 分钟前
🪦 话说……Flutter 真要凉了吗?那些瞎吵吵的背后到底咋回事儿?
前端
星眠14 分钟前
移动端下拉刷新的实现
javascript·面试
张志鹏PHP全栈14 分钟前
Vue3第八天,watch监听函数
前端·vue.js
月阳羊17 分钟前
【硬件-笔试面试题】硬件/电子工程师,笔试面试题-50,(知识点:TCP/IP 模型)
经验分享·嵌入式硬件·网络协议·面试·职场和发展