原型
何为原型对象?
构造函数都有一个prototype属性,这个属性指向的就是原型对象(简称原型)。
何为原型链?
每个对象都有一个proto属性指向原型对象,原型对象也有一个proto属性指向原型对象的原型对象,一直往上找,直到找到Object对象,Object对象的原型对象为null。这个像链式一样的结构称为原型链。
构造函数与对象实例及原型对象的关系
构造函数的prototype属性指向原型对象,原型对象有一个constructor属性指回构造函数。
每个构造函数生成的实例对象都有一个proto属性,这个属性也指向原型对象。
闭包
什么是闭包?
闭包就是能读取到其他函数内部变量的函数。
eg.函数A中的函数B,被函数A外部的一个变量引用的时候,就创建了一个闭包。
执行环境(执行上下文)
JavaScript(单线程)处理多个执行上下文的方式——栈。
函数执行上下文只有在执行函数时才会创建。
闭包举例
-不能理解之闭包-for(var i = 0;i < 5; i++){setTimeout(function(){console.log(i++);},1000);}console.log(i)// 5 5 6 7 8 9为什么会在4秒后一次性会输出5,6,7,8,9呢?-setTimeout是异步宏任务,不会直接执行,而会被放入任务队列里面,等待所有的同步代码执行完毕后才会执行。而你提到的为什么会一下输出56789,是因为在同步代码中通过for循环在极短的时间内就将5个异步任务放入了任务队列,他们几乎同时开始计时。所以隔了4秒后,所有的任务几乎同时完成。完成的任务会一个一个的从任务队列中取出,来到主线程中(也就是同步任务执行的线程)。-1-function outerFn(){var i = 0;function innerFn(){i++;console.log(i);}return innerFn;}var inner = outerFn();inner();//1inner();//2inner();//3var inner2 = outerFn();inner2();//1inner2();//2inner2();//3-2-var i = 0; //注意此时i声明在外层function outerFn(){function innnerFn(){i++;console.log(i);}return innnerFn;}var inner1 = outerFn();var inner2 = outerFn();inner1();//1inner2();//2inner1();//3inner2();//4
[微任务]包括:Promise , process.nextTick() *node.js里面的 [宏任务]包括:整体代码script, setTimeout setInterval
闭包的优缺点
闭包的好处及坏处
优点:
1.缓存
2.面向对象中的对象
3.实现封装,防止变量跑到外层作用域中,发生命名冲突
4.匿名自执行函数,匿名自执行函数可以减小内存消耗
缺点:
1.内存消耗
2.性能问题
事件冒泡
点击子元素,父元素的click时间同样会触发。
使用event.stopPropagation()阻止冒泡。
回调函数
- 你定义的
- 你没有调
- 但它最终执行了
递归调用
在函数内部调用自己延时调用
setTimeout(function(){},3000};typeof instanceof ===
typeof
返回数据类型的字符串表达。
null 和 array 返回的是object。instanceof(instance-实例)
可以判断具体的数据类型。用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
console.log(Object instanceof Object);//trueconsole.log(Function instanceof Function);//trueconsole.log(Number instanceof Number);//falseconsole.log(String instanceof String);//falseconsole.log(Function instanceof Object);//trueconsole.log(Foo instanceof Function);//trueconsole.log(Foo instanceof Foo);//false
===
undefined 和 null 的区别
undefined-定义未赋值
null-定义赋值了,值为null
何时给变量赋值为null?
- 以 函数 形式调用 window (严格模式下指向undefined)
- 以 方法 形式调用 调用方法的那个对象
- 以 构造函数 调用 新创建的那个对象
-
call、apply、bind的区别
都是改变this的指向,传入的第一个参数都是this的指向
- call 和 apply 的区别——当传入多个变量时,call是参数列表,apply是数组
-
forEach和map的区别
都是遍历数组
- map()方法会得到一个新的数组并返回(会分配内存空间存储新数组并返回)
- forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。
深拷贝和浅拷贝
JavaScript 题集(更新中)防抖 节流
引用文章-js防抖和节流By沐子馨在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。
防抖
函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
// 防抖function debounce(func, wait=0) {if (typeof func !== 'function') {throw new TypeError('need a function arguments')}let timeid = null;let result;return function() {let context = this;let args = arguments;if (timeid) {clearTimeout(timeid);}timeid = setTimeout(function() {result = func.apply(context, args);}, wait);return result;}}// 处理函数function handle() {console.log(Math.random());}// 滚动事件window.addEventListener('scroll', debounce(handle, 1000));
当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。
节流
函数节流(throttle):当持续触发事件时,保证一定时间段内只调用一次事件处理函数。
// 节流throttle代码(时间戳)var throttle = function(func, delay) {var prev = Date.now();return function() {var context = this;var args = arguments;var now = Date.now();if (now - prev >= delay) {func.apply(context, args);prev = Date.now();}}}function handle() {console.log(Math.random());}window.addEventListener('scroll', throttle(handle, 1000));
当高频事件触发时,第一次会立即执行(给scroll事件绑定函数与真正触发事件的间隔一般大于delay,如果你非要在网页加载1000毫秒以内就去滚动网页的话,我也没办法o(╥﹏╥)o),而后再怎么频繁地触发事件,也都是每delay时间才执行一次。而当最后一次事件触发完毕后,事件也不会再被执行了 (最后一次触发事件与倒数第二次触发事件的间隔小于delay,为什么小于呢?因为大于就不叫高频了呀(╹▽╹))。
// 节流throttle代码(定时器):var throttle = function(func, delay) {var timer = null;return function() {var context = this;var args = arguments;if (!timer) {timer = setTimeout(function() {func.apply(context, args);timer = null;}, delay);}}}function handle() {console.log(Math.random());}window.addEventListener('scroll', throttle(handle, 1000));
当触发事件的时候,我们设置一个定时器,再次触发事件的时候,如果定时器存在,就不执行,直到delay时间后,定时器执行执行函数,并且清空定时器,这样就可以设置下个定时器。当第一次触发事件时,不会立即执行函数,而是在delay秒后才执行。而后再怎么频繁触发事件,也都是每delay时间才执行一次。当最后一次停止触发后,由于定时器的delay延迟,可能还会执行一次函数。
节流中用时间戳或定时器都是可以的。更精确地,可以用时间戳+定时器,当第一次触发事件时马上执行事件处理函数,最后一次触发事件后也还会执行一次事件处理函数。
// 节流throttle代码(时间戳+定时器):var throttle = function(func, delay) {var timer = null;var startTime = Date.now();return function() {var curTime = Date.now();var remaining = delay - (curTime - startTime);var context = this;var args = arguments;clearTimeout(timer);if (remaining <= 0) {func.apply(context, args);startTime = Date.now();} else {timer = setTimeout(func, remaining);}}}function handle() {console.log(Math.random());}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
