2022前端⼤⼚⾯试题之JavaScript篇(1)
⽂章⽬录
同步任务是指在主线程上排队执⾏的任务,只有前⼀个任务执⾏完毕,才能继续执⾏下⼀个任务,当我们打开⽹站时,⽹站的渲染过程,⽐如元素的渲染,其实就是⼀个同步任务。 异步任务是指不进⼊主线程,⽽进⼊任务队列的任务,只有任务队列通知主线程,某个异步任务可以执⾏了,该任务才会进⼊主线程。异步模式:每⼀个任务有⼀个或多个回调函数(callback),前⼀个任务结束后,不是执⾏后⼀个任务,⽽是执⾏回调函数,后⼀个任务则是不等前⼀个任务结束就执⾏,所以程序的执⾏顺序与任务的排列顺序是不⼀致的、异步的。当我们打开⽹站时,像图⽚的加载,⾳乐的加载,其实就是⼀个异步任务。在浏览器端,耗时很长的操作都应该异步执⾏,避免浏览器失去响应,最好的例⼦就是Ajax操作。 JavaScript的异步机制: (1)所有同步任务都在主线程上执⾏,⾏成⼀个执⾏栈 (2)主线程之外,还存在⼀个任务队列,只要异步任务有了结果,就会在任务队列中放置⼀个事件 (3)⼀旦执⾏栈中的所有同步任务执⾏完毕,系统就会读取任务队列,看看⾥⾯还有哪些事件,那些对应的异步任务,于是结束等待状态,进⼊执⾏栈,开始执⾏ (4)主线程不断的重复上⾯的第三步
1.回调函数:这是异步编程最基本的⽅法。 回调函数:当⼀个函数作为参数传⼊另⼀个参数中,并且它不会⽴即执⾏,只有当满⾜⼀定条件后该函数才可以执⾏,这种函数就称为回调函数。它的优点是简单
、容易理解和部署,缺点是多个回调函数嵌套的时候会造成回调地狱,上下两层的回调函数间的代码耦合度太⾼,不利于代码的可维护。
2.事件监听:事件驱动模式。任务的执⾏不取决于代码的顺序,⽽取决于某个事件是否发⽣。
3.发布/订阅:假定存在⼀个"信号中⼼",某个任务执⾏完成,就向信号中⼼"发布"⼀个信号,其他任务可以向信号中⼼"订阅"这个信号,从⽽知道什么时候⾃⼰可以开始执⾏,⼜称"观察者模式"。
4.Promise:可以将嵌套的回调函数作为链式调⽤。每⼀个异步任务返回⼀个Promise对象,该对象有⼀个then⽅法,允许指定回调函数。f1().then(f2);//f1的回调函数f2但有时会造成多个 then 的链式调⽤,造成代码语义不够明确。
5.Generator:ES6 提供的⼀种异步编程解决⽅案,当遇到异步函数执⾏的时候,将函数执⾏权转移出去,当异步函数执⾏完毕时再将执⾏权给转移回来。
6.async/await:generator 和 promise 实现的⼀个⾃动执⾏的语法糖。相对于Promise,优势:处理 then 的调⽤链,能够更清晰准确的写出代码;并且也能优雅地解决回调地狱问题。缺点:因为 await 将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使⽤了 await 会导致性能上的降低,代码没有依赖性的话,完全可以使⽤ Promise.all 的⽅式。
回调函数中嵌套回调函数的情况就叫做回调地狱。如何解决回调地狱: 1.Promise:
Promise构造函数接收⼀个函数作为参数,我们需要处理的异步任务就卸载该函数体内,该函数的两个参数是resolve,reject。异步任务执⾏成功时调⽤resolve函数返回结果,反之调⽤reject。
Promise对象的then⽅法⽤来接收处理成功时响应的数据,catch⽅法⽤来接收处理失败时相应的数据。
Promise的链式编程可以保证代码的执⾏顺序,前提是每⼀次在than做完处理后,⼀定要return⼀个Promise对象,这样才能在下⼀次then时接收到数据。
2.async/await:
async关键字,他作为⼀个关键字放到声明函数前⾯,表⽰该函数为⼀个异步任务,不会阻塞后⾯函数的执⾏。
await关键字只能在使⽤async定义的函数中使⽤,await后⾯可以直接跟⼀个 Promise实例对象,await可以直接拿到Promise中resolve中的数据。
JavaScript this 关键字
在⽅法中,this 表⽰该⽅法所属的对象(上级对象)。
如果单独使⽤,this 表⽰全局对象。在浏览器中,window 就是该全局对象为 [object Window]。
在函数中,this 表⽰全局对象。在浏览器中,window 就是该全局对象为 [object Window]。
在函数中,在严格模式下,this 是未定义的(undefined),因为严格模式下不允许默认绑定。
在事件中,this 表⽰接收事件的元素。在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素
类似 call() 和 apply() ⽅法可以将 this 引⽤到任何对象。
基本数据类型指的是简单的数据段,引⽤数据类型指的是有多个值构成的对象。常见的基本数据类型:Number、String 、Boolean、Null和Undefined。存储在栈中的简单数据段,基本数据类型是按值访问的。引⽤类型数据:也就是对象类型Object type,⽐如:Object 、Array 、Function 、Data等。存储在堆中的对象,即存储在变量处的值是⼀个指针。与其他语⾔的不同是,你不可以直接访问堆内存空间中的位置和操作堆内存空间。只能操作对象在栈内存中的引⽤地址。
引⽤类型数据在栈内存中保存的实际上是对象在堆内存中的引⽤地址。通过这个引⽤地址可以快速查到保存中堆内存中的对象。①所有引⽤类型,对象都有⼀个__proto__(隐式原型)属性,属性值是⼀个普通的对象
②所有函数都有⼀个prototype(显式原型)属性,属性值是⼀个普通的对象 ③构造函数(可以⽤来new的函数就叫构造函数,箭头函数不能⽤来当做构造函数)的prototype和其实例的__proto__是指向同⼀个地⽅的,这个地⽅就叫做原型对象var  a = 10;var  b = a ;b = 20;console .log (a ); // 10值//上⾯,b 获取的是a 值得⼀份拷贝,虽然,两个变量的值相等,//但是两个变量保存了两个不同的基本数据类型值。//b 只是保存了a 复制的⼀个副本。所以,b 的改变,对a 没有影响。var  obj1 = new  Object ();var  obj2 = obj1;obj2.name = "我有名字了";console .log (obj1.name ); // 我有名字了//说明这两个引⽤数据类型指向了同⼀个堆内存对象。obj1赋值给onj2,//实际上这个堆内存对象在栈内存的引⽤地址复制了⼀份给了obj2,//但是实际上他们共同指向了同⼀个堆内存对象。实际上改变的是堆内存对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var  a = [1,2,3];a .__proto__ === Array .prototype ; // true function  Person (name , age ) {  this .name = name  this .age = age }Person .prototype .sayName  = function () {  console .log (this .name )}const  person1 = new  Person ('⼩明', 20)console .log (Person .prototype === person1.__proto__) // true console .log (Function .prototype === Person .__proto__) // true console .log (Function .prototyp
e === Object .__proto__) // true ,function Object()其实也是个函数,所以他是Function 构造函数的实例console .log (Function .prototype === Function .__proto__) // true console .log (Person .prototype .constructor === Person ) // true console .log (Person .prototype .__proto__ === Object .prototype ) // true console .log (Function .prototype .__proto__ === Object .prototype ) // true console .log (Object .prototype .__proto__ === null ) // true console .log (Person .prototype .__proto__ === Function .prototype ) // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Function是⼀个构造函数,他有显式原型对象,这个显式原型对象是对象(⽽⾮函数)的⼀个实例,所以他有隐式原型,指向他的构造函数的显式原型,也就是Function.prototype.__proto__ === Object.prototype,⼀个具体函数Person的隐式原型也是Object.prototype:
javascript属于前端吗
Person.prototype.__proto__ === Object.prototype
此图原型链
当访问⼀个对象的某个属性时,会先在这个对象本⾝属性上查,如果没有到,则会去它的__proto__隐式原型上查,即它的构造函数的prototype,如果还没有到就会再在构造函数的prototype的__proto__中查,这样⼀层⼀层向上查就会形成⼀个链式结构,我们称为原型链。
Object.prototype其实也有__proto__,指向null,那才是原型链的终点。function  Parent (month ){    this .month = month ;}var  child = new  Parent ('Ann');console .log (child .month ); // Ann console .log (child .father ); // undefined
1
2
3
4
5
6
在child中查某个属性时,会执⾏下⾯步骤:
constructor和prototype是成对的,你指向我,我指向你。
原型继承
原型继承:实例可以使⽤构造函数上的prototype中的⽅法。
防抖和节流
防抖 (debounce):防⽌抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。有个需要频繁触发的函数在规定时间内,只让最后⼀次⽣效,前⾯不⽣效。代码实现重在清零 clearTimeout。
节流(throttle):控制流量,单位时间内事件只能触发⼀次。⼀个函数执⾏⼀次后,只有⼤于设定的执⾏周期后才会执⾏第⼆次。有个需要频繁触发的函数,处于优化性能⾓度,在规定时间内,只让函数触发的第⼀次⽣效,后⾯不⽣效。所以节流会稀释函数的执⾏频率。代码实现重在开锁关锁。
宏任务与微任务
宏任务:当前调⽤栈中执⾏的代码成为宏任务。(主代码快,定时器等等)。 e.g.:I/O、setTimeout、setInterval、setImmediate、requestAnimationFrame function  Person (name ) { // 构造函数  this .name = name }Person .prototype .sayName  = function () { // 往原型对象添加⽅法  console .log (this .name )}const  person = new  Person ('zagiee') // 实例// 使⽤构造函数的prototype 中的⽅法person .sayName () // zagiee console .log (Person instanceof  Function ) // true console .log (Person instanceof  Object ) // true console .log (person instanceof  Person ) // true console .log (person instanceof  Object ) // true
1
2
3
4
5
6
7
8
9
10
11
12
1314<button id ="btn">按钮</button >function  debounce (fn , delay ) {  //记录上⼀次的延时器  let  timer = null ;  return  function  () {    // 清楚上⼀次延时器    clearTimeout (timer );    //重新设置新的延时器    timer = setTimeout (function  () {      fn .apply (this );    },delay );  }}document .getElementById ('btn').onclick = debounce (function  () {console .log ('点击事件被触发了' + Date .now ())},1000);
1
2
3
4
5
6
7
8
9
10
1112
13
14
15function  throttle (fn , wait ) {  //记录上⼀次函数触发时间  let  lastTime = 0;  return  function  () {    let  nowTime = Date .now ();    if  (nowTime - lastTime > wait ) {      //修正this 指向问题      fn .call (this );      //同步时间      lastTime = nowTime ;    }  };}document .onscroll = throttle (function  () {console .log ('scroll 事件被触发了' + Date .now ())},200);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。