原型

何为原型对象?

构造函数都有一个prototype属性,这个属性指向的就是原型对象(简称原型)。

何为原型链?

每个对象都有一个proto属性指向原型对象,原型对象也有一个proto属性指向原型对象的原型对象,一直往上找,直到找到Object对象,Object对象的原型对象为null。这个像链式一样的结构称为原型链。

构造函数与对象实例及原型对象的关系

构造函数的prototype属性指向原型对象,原型对象有一个constructor属性指回构造函数。
每个构造函数生成的实例对象都有一个proto属性,这个属性也指向原型对象。

JavaScript基础 - 图1

闭包

什么是闭包?

闭包就是能读取到其他函数内部变量的函数。
eg.函数A中的函数B,被函数A外部的一个变量引用的时候,就创建了一个闭包。

执行环境(执行上下文)

JavaScript(单线程)处理多个执行上下文的方式——栈。
函数执行上下文只有在执行函数时才会创建。

闭包举例

链接

  1. -不能理解之闭包-
  2. for(var i = 0;i < 5; i++){
  3. setTimeout(function(){
  4. console.log(i++);
  5. },1000);
  6. }
  7. console.log(i)// 5 5 6 7 8 9
  8. 为什么会在4秒后一次性会输出56789呢?
  9. -setTimeout是异步宏任务,不会直接执行,而会被放入任务队列里面,
  10. 等待所有的同步代码执行完毕后才会执行。
  11. 而你提到的为什么会一下输出56789,是因为在同步代码中通过for循环在极短的时间内
  12. 就将5个异步任务放入了任务队列,他们几乎同时开始计时。
  13. 所以隔了4秒后,所有的任务几乎同时完成。
  14. 完成的任务会一个一个的从任务队列中取出,来到主线程中(也就是同步任务执行的线程)。
  15. -1-
  16. function outerFn(){
  17. var i = 0;
  18. function innerFn(){
  19. i++;
  20. console.log(i);
  21. }
  22. return innerFn;
  23. }
  24. var inner = outerFn();
  25. inner();//1
  26. inner();//2
  27. inner();//3
  28. var inner2 = outerFn();
  29. inner2();//1
  30. inner2();//2
  31. inner2();//3
  32. -2-
  33. var i = 0; //注意此时i声明在外层
  34. function outerFn(){
  35. function innnerFn(){
  36. i++;
  37. console.log(i);
  38. }
  39. return innnerFn;
  40. }
  41. var inner1 = outerFn();
  42. var inner2 = outerFn();
  43. inner1();//1
  44. inner2();//2
  45. inner1();//3
  46. inner2();//4

[微任务]包括:Promise , process.nextTick() *node.js里面的 [宏任务]包括:整体代码script, setTimeout setInterval

闭包的优缺点

闭包的好处及坏处
优点
1.缓存
2.面向对象中的对象
3.实现封装,防止变量跑到外层作用域中,发生命名冲突
4.匿名自执行函数,匿名自执行函数可以减小内存消耗
缺点
1.内存消耗
2.性能问题

事件冒泡

点击子元素,父元素的click时间同样会触发。
使用event.stopPropagation()阻止冒泡。

回调函数

  1. 你定义的
  2. 你没有调
  3. 但它最终执行了

    递归调用

    在函数内部调用自己

    延时调用

    setTimeout(function(){},3000};

    typeof instanceof ===

    typeof

    返回数据类型的字符串表达。
    null 和 array 返回的是object。

    instanceof(instance-实例)

    可以判断具体的数据类型。

    用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

  1. console.log(Object instanceof Object);//true
  2. console.log(Function instanceof Function);//true
  3. console.log(Number instanceof Number);//false
  4. console.log(String instanceof String);//false
  5. console.log(Function instanceof Object);//true
  6. console.log(Foo instanceof Function);//true
  7. console.log(Foo instanceof Foo);//false

===

可以判断null,undifined。

undefined 和 null 的区别

undefined-定义未赋值
null-定义赋值了,值为null

何时给变量赋值为null?

  1. 初始赋值,表明将要赋值为对象;
  2. 结束前,让对象成为垃圾对象(被浏览器回收)。

    this 指向

  • 以 函数 形式调用 window (严格模式下指向undefined)
  • 以 方法 形式调用 调用方法的那个对象
  • 以 构造函数 调用 新创建的那个对象
  • call&apply 指定的那个对象

    call、apply、bind的区别

  • 都是改变this的指向,传入的第一个参数都是this的指向

  • call 和 apply 的区别——当传入多个变量时,call是参数列表,apply是数组
  • bind和call类似,区别在于立即执行还是等待执行

    forEach和map的区别

  • 都是遍历数组

  • map()方法会得到一个新的数组并返回(会分配内存空间存储新数组并返回)
  • forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。

    深拷贝和浅拷贝

    JavaScript 题集(更新中)

    防抖 节流

    引用文章-js防抖和节流By沐子馨

    在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。

防抖

函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

  1. // 防抖
  2. function debounce(func, wait=0) {
  3.    if (typeof func !== 'function') {
  4.     throw new TypeError('need a function arguments')
  5.    }
  6.    let timeid = null;
  7. let result;
  8.    return function() {
  9.     let context = this;
  10.     let args = arguments;
  11.     if (timeid) {
  12.       clearTimeout(timeid);
  13.     }
  14.     timeid = setTimeout(function() {
  15.       result = func.apply(context, args);
  16.     }, wait);
  17.     return result;
  18.    }
  19. }
  20. // 处理函数
  21. function handle() {
  22. console.log(Math.random());
  23. }
  24. // 滚动事件
  25. window.addEventListener('scroll', debounce(handle, 1000));

当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。

节流

函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

  1. // 节流throttle代码(时间戳)
  2. var throttle = function(func, delay) {
  3.   var prev = Date.now();
  4.   return function() {
  5.     var context = this;
  6.     var args = arguments;
  7.     var now = Date.now();
  8.     if (now - prev >= delay) {
  9.       func.apply(context, args);
  10.       prev = Date.now();
  11.     }
  12.   }
  13. }
  14. function handle() {
  15.   console.log(Math.random());
  16. }
  17. window.addEventListener('scroll', throttle(handle, 1000));

当高频事件触发时,第一次会立即执行(给scroll事件绑定函数与真正触发事件的间隔一般大于delay,如果你非要在网页加载1000毫秒以内就去滚动网页的话,我也没办法o(╥﹏╥)o),而后再怎么频繁地触发事件,也都是每delay时间才执行一次。而当最后一次事件触发完毕后,事件也不会再被执行了 (最后一次触发事件与倒数第二次触发事件的间隔小于delay,为什么小于呢?因为大于就不叫高频了呀(╹▽╹))。

  1. // 节流throttle代码(定时器):
  2. var throttle = function(func, delay) {
  3. var timer = null;
  4. return function() {
  5. var context = this;
  6. var args = arguments;
  7. if (!timer) {
  8. timer = setTimeout(function() {
  9. func.apply(context, args);
  10. timer = null;
  11. }, delay);
  12. }
  13. }
  14. }
  15. function handle() {
  16. console.log(Math.random());
  17. }
  18. window.addEventListener('scroll', throttle(handle, 1000));

当触发事件的时候,我们设置一个定时器,再次触发事件的时候,如果定时器存在,就不执行,直到delay时间后,定时器执行执行函数,并且清空定时器,这样就可以设置下个定时器。当第一次触发事件时,不会立即执行函数,而是在delay秒后才执行。而后再怎么频繁触发事件,也都是每delay时间才执行一次。当最后一次停止触发后,由于定时器的delay延迟,可能还会执行一次函数。
节流中用时间戳或定时器都是可以的。更精确地,可以用时间戳+定时器,当第一次触发事件时马上执行事件处理函数,最后一次触发事件后也还会执行一次事件处理函数。

  1. // 节流throttle代码(时间戳+定时器):
  2. var throttle = function(func, delay) {
  3. var timer = null;
  4. var startTime = Date.now();
  5. return function() {
  6. var curTime = Date.now();
  7. var remaining = delay - (curTime - startTime);
  8. var context = this;
  9. var args = arguments;
  10. clearTimeout(timer);
  11. if (remaining <= 0) {
  12. func.apply(context, args);
  13. startTime = Date.now();
  14. } else {
  15. timer = setTimeout(func, remaining);
  16. }
  17. }
  18. }
  19. function handle() {
  20. console.log(Math.random());
  21. }
  22. window.addEventListener('scroll', throttle(handle, 1000));

在节流函数内部使用开始时间startTime、当前时间curTime与delay来计算剩余时间remaining,当remaining<=0时表示该执行事件处理函数了(保证了第一次触发事件就能立即执行事件处理函数和每隔delay时间执行一次事件处理函数)。如果还没到时间的话就设定在remaining时间后再触发 (保证了最后一次触发事件后还能再执行一次事件处理函数)。当然在remaining这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。

总结

函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。

函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。

区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

哪些方法会中断js执行?

链接:https://www.nowcoder.com/questionTerminal/f82d41f7f8044491be84cf6b718abf6c?orderByHotValue=1&page=1
来源:牛客网

  • 异步,不会阻碍代码的执行,它会等待所有的同步代码执行完毕后,再执行输出自己的同步结果。(原生js中,只有定时器,DOM,ajax三个东西是异步的。)setTimeout fetch async (参考链接https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html)
  • 同步,代码只会从上到下依次执行,只要一步出错,接下来的代码就会无法执行alert sync