具体内容能够查看笔记

1、节流throttle 和 防抖debounce

防抖和节流的作用:当某一个操作被用户频繁触发时,例如window的onresize,input的oninput等,应用防抖和节流能无效管制callback的触发频率
应用形式:input.addEventListenter("input",debounce(handle,delay))

防抖

const debounce = (callback,delay)=>{    let timer = null    return function(){        if(timer != null) clearTimeout(timer)        timer = setTimeout(()=>{callback.apply(this,arguments)},delay)    }}

节流

形式(1)

const throttle = (callback,delay)=>{    let prev = Date.now()    return function (){        let now = Date.now()        if(now-prev>delay){            callback.apply(this,arguments)            prev = Date.now()        }    }}

缺点:必须期待wai工夫能力首次点击,因为throttle()初始化了prev工夫,若此时点击,则now-prev<wait,不会执行callback。并且,进行点击后,不肯定会触发之前的callback

形式(2)

const throttle = (callback,delay)=>{    let timer = null    return function(){        if(!timer){            setTimeout(()=>{                callback.apply(this,arguments)                timer = null            },delay)        }    }}

缺点:首次点击必然会执行,但要期待wai工夫才有成果,因为是setTimeout定时器,并且在定时器正在执行中的时候,因为timer=null,此时间断触发的话,会产生多个定时器

综合两者

const throttle = (callback, delay) => {    let prev = Date.now()    let timer = null    return function () {        let now = Date.now()        let surplus = delay - (now - prev)        clearTimeout(timer)        if (surplus <= 0) {            callback.apply(this, arguments)                prev = Date.now()        } else {            timer = setTimeout(() => {                callback.apply(this, arguments)            }, surplus)        }    }}

2、获取元素行间款式

dom.currentStyle.left || getComputedStyle(dom,null).left

备注:getComputedStyle第二个参数,用来获取伪元素的属性,例如getComputedStyle(dom,"after").width

3、元素地位offsetWidth等属性

一个元素div,通常有width,padding,margin,border

dom.clientWidth : width + padding
dom.offsetWidth : width + padding + border

dom.offsetLeft : 绝对于定位父级(position:relative)的left值
dom.offsetParent : 定位父级元素(通常状况下,要 dom.offsetParent.tagName 去拿到父级的tagName)

height与width雷同

4、节流优化resize

(function () {    var throttle = function (type, name, obj) {        obj = obj || window;           var running = false;           var func = function () {               if (running) {                      return;               }               running = true;               requestAnimationFrame(function () {                   obj.dispatchEvent(new CustomEvent(name));                   running = false;               });           };           obj.addEventListener(type, func);    };    throttle("resize", "optimizedResize");})();window.addEventListener("optimizedResize", ()=>{});

5、原型、原型链

如果看不到图片:请先点击参考链接再回到本页面刷新就有图片了

原型的概念
每个javascript对象(null除外)创立的时候,就会给它关联一个对象,这个对象就是咱们说的原型,每个对象都会从原型中继承属性。

(1)每个函数都有prototype,指向函数的原型(这玩意就是函数的原型),原型也是一个对象

(2)每个对象都有__proto__,对象的原型(用来连贯实例和构造函数),值为:构造函数的prototype。(构造函数的prototype,不就是构造函数的原型嘛,所以这玩意也是构造函数的原型)

function Parent(){}const parent1 = new Parent()parent1.__proto__ = Parent.prototype

(3)constructor:每个原型都有一个constructor属性,指向关联的构造函数

function Parent(){} //构造函数Parent.prototyoe.constructor = Parent //Parent.prototype是构造函数的原型

之前有一个误区:

function Person(){}const person1 = new Person()console.log(person1.constructor) //Person

其实person1并没有constructor这个属性,因而,去它的原型__proto__下面找,也就是构造函数Person.prototype下面找。正好Person.prototype.constructor = Person

(4)instanceof:判断是否是实例

function A() {}const a = new A()console.log(a instanceof A) //truea.__proto__ = {}  console.log(a instanceof A) //false

从这个例子能够看出:a和A要在同一个原型链上,a instanceof A才为true,扭转了a的原型__prpto__之后,就为false了

原型链
之前说了,原型(构造函数的prototype)也是一个对象。既然是对象,它也有原型。

原型的构造函数是Object

因而, (构造函数.prototype).__prpto__ = Object.prototype // (构造函数.prototype)是一个对象

最初:js规定,Object.prototype的原型指向null。
因而原型链如下图

例题

Function.prototype.a = 1;Object.prototype.b = 2;function A() {}var a = new A();console.log(A.a, A.b); // 1 2console.log(a.a, a.b); // undefined 2console.log(Function.b, Object.a); // 2 1

6、手写一个new函数

new 次要实现了4个操作:
(1)创立一个空对象
(2)链接原型
(3)绑定this
(4)返回一个对象

function create() {  const args = arguments  const obj = new Object() //翻新空对象  const cradleFn = [].shift.call(args) //拿到构造函数  obj.__proto__ = cradleFn.prototype //链接原型  const result = cradleFn.apply(obj, args) //绑定this  return (typeof result == "object" ? result : obj)}

7、new 构造函数返回值问题

new 总是会返回对象,如果构造函数外面有return {},则返回这个{},否则返回this实例

function A(){    return 123}const a = new A() //a为{}function B(){    return {name:123}}const b = new B() //b为{name:123}

8、如何判断一个函数是否由new调用

(1)instanceoffunction A(){    if(this instanceof A){}}(2)new.targetfunction B(){    if(new.target === B){}}

9、继承

(1)call办法

function Parent(){    this.name = "zhang"    this.age = 35}function Child(){    Parent.call(this)    this.age = 15}const son = new Child()console.log(son.name) //zhangconsole.log(son.age)  //15

毛病:无奈继承Parent.prototype上的值

(2)原型

function Parent(){    this.name = "zhang"    this.arr = [1,2,3]}function Child(){    this.age = 15}Child.prototype = new Parent()

毛病:this.arr是专用的,一旦其中一个实例更改了arr,其余实例的arr属性也会更改

(3)call、原型组合形式

function Parent(){    this.arr = [1,2,3]    this.name = "zhang"}function Child(){    Parent.call(this)}Child.prototype = Object.create(Parent.prototype) //关键点

10、call、apply惯例应用

Math.max.apply(null,[2,5,3,7,1])
Array.prototype.slice.call({1:"zhang",2:true,length:5}) //类数组(有length属性),转真正数组

11、浏览器同源策略

软大神的具体文档

同源:协定(http)、域名(www.xx.com)、端口号(:8080)必须都雷同
阮大神说:
非同源时,次要三种行为受到限制
(1) Cookie、LocalStorage 和 IndexDB 无奈读取
(2) DOM 无奈取得
(3) AJAX 申请不能发送

12、回流(重排)与重绘

参考资料

回流:当浏览器必须重新处理和绘制局部或全副页面时,回流就会产生。我了解为,浏览器依据renderTree计算出元素盒子的几何信息(地位、大小)
重绘:依据回流计算的几何信息,转换成理论像素

何时触发回流:

  • 增加或删除可见的DOM元素
  • 元素的地位发生变化
  • 元素的尺寸发生变化(包含外边距、内边框、边框大小、高度和宽度等)
  • 内容发生变化,比方文本变动或图片被另一个不同尺寸的图片所代替
  • 页面一开始渲染的时候(这必定防止不了)
  • 浏览器的窗口尺寸变动(因为回流是依据视口的大小来计算元素的地位和大小的)
    留神:回流肯定会触发重绘,而重绘不肯定会回流

获取哪些属性会触发回流重绘:

  • offsetTop、offsetLeft、offsetWidth、offsetHeight
  • scrollTop、scrollLeft、scrollWidth、scrollHeight
  • clientTop、clientLeft、clientWidth、clientHeight
  • getComputedStyle
  • getBoundingClientRect

如何缩小回流重绘:
1、应用style.cssText和className

  • el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;';
  • el.className += ' active';

2、批量批改DOM
(1) 使元素脱离文档流
(2)对其进行屡次批改
(3)将元素带回到文档中

3、防止触发同步布局事件(循环中获取触发回流重绘的属性)

function initP() {    for (let i = 0; i < paragraphs.length; i++) {        paragraphs[i].style.width = box.offsetWidth + 'px';    }}

4、css3硬件加速

  • transform
  • opacity
  • filters

13、try{...}catch捕捉谬误

(1)之前

try{    a}catch(e){}

无奈捕捉谬误:a.在语法检测时就出错了,此时主线程尚未执行try
(2)之中

try{    a.b}catch(e){}

能够捕捉:a.b未定义
(3)之后

try{    setTimeout(()=>{        a.b    },100)}catch(e){}

无奈捕捉:try曾经执行实现了

总结:能被 try catch 捕捉到的异样,必须是在报错的时候,线程执行曾经进入 try catch 代码块,且处在 try catch 外面,这个时候能力被捕捉到。

14、执行上下文、作用域、作用域链

执行上下文:执行上下文是评估和执行 JavaScript 代码的环境的抽象概念,每当 Javascript 代码在运行的时候,它都是在执行上下文中运行(了解:全局js代码或者函数在执行之前,会先做两件事:绑定this,同时创立一个蕴含变量和函数的环境)

执行上下文参考文档

作用域:存储和拜访变量的区域
作用域链:函数执行上下文内,拜访变量时,若不存在,就拜访该函数内部的执行上下文,若还不存在,就持续拜访内部的上下文,始终到全局的执行上下文,这样就造成了一个作用域链

15、for in,Object.keys,Object.getPropertyNames之间的区别

function Parent() {}Parent.color = "salmon"Parent.prototype.pro = "pro"const obj = new Parent()obj.name = "zhang"Object.defineProperties(obj, {  gender: {    value: "male",    enumerable: false  }})for (var key in obj) {  console.log("key=", key, "value=", obj[key])}// key= name value= zhang// key= pro value= proconsole.log(Object.keys(obj)) //["name"]console.log(Object.getOwnPropertyNames(obj)) //["name","gender"]

for in 能够拜访本身和原型链上的属性
Object.keys只能拜访本身可枚举的属性
Object.getOwnPropertyNames能拜访本身所有属性(可枚举和不可枚举)

16、EventLoop 事件循环、宏工作、微工作

参考文档讲得通俗易懂

17、TCP/IP三次挥手、四次握手

参考文档
http1.0、2.0、https参考文档

18、强缓存vs协商缓存

参考文档

19、浏览器输出url之后产生了什么

参考文档

20、算法

(1)冒泡算法

  function bubbleSort(arr) {    if (!arr || !arr.length) return    for (let i = 0; i < arr.length - 1; i++) {      for (let j = 0; j < arr.length - 1 - i; j++) {        if (arr[j] > arr[j + 1]) {          [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]        }      }    }    return arr  }

(2)抉择排序

  function selectSort(arr) {    if (!arr || !arr.length) return    for (let i = 0; i < arr.length; i++) {      for (let j = i; j < arr.length; j++) { // 这里要留神:j = i        if (arr[j] < arr[i]) {          [arr[j], arr[i]] = [arr[i], arr[j]]        }      }    }    return arr  }

(3)插入排序

  Array.prototype.insertSort = function () {    let arr = [].slice.call(this)    for (let i = 1; i < arr.length; i++) { //留神,这里是i=1      for (let j = i; j > 0; j--) { //留神,这里是倒序        if (arr[j] < arr[j - 1]) {          [arr[j], arr[j - 1]] = [arr[j - 1], arr[j]]        } else {          break        }      }    }    return arr  }

(4)疾速排序

  Array.prototype.quickSort = function () {    const arr = [].slice.call(this)    if (arr.length < 1) return arr //递归进口    let left = [],      right = [],      cur = arr.splice(0, 1)    for (let i = 0; i < arr.length; i++) {      if (arr[i] < cur) {        left.push(arr[i])      } else {        right.push(arr[i])      }    }    return [].quickSort.call(left).concat(cur, [].quickSort.call(right))  }

21、堆栈、队列

堆栈:后进先出
队列:先到先得

22、模仿call、apply、bind

call办法:

  Function.prototype.callFn = function (context) {    context = context || window    context.fn = this    var args = []    for (var i = 1; i < arguments.length; i++) {      args.push("arguments[" + i + "]")    }    var result = eval("context.fn(" + args + ")")    delete context.fn    return result  }

apply办法

  Function.prototype.applyFn = function (context, arr = []) {    context = context || window    context.fn = this    var args = []    for (var i = 0; i < arr.length; i++) {      args.push("arr[" + i + "]")    }    var result = eval("context.fn(" + args + ")")    delete context.fn    return result  }

bind办法

  Function.prototype.bindFn = function (context) {    if (typeof this != "function") {      throw new Error("必须是函数")    }    var outerArgs = [].shift.call(arguments)    var self = this    var resultFn = function () {      var innerArgs = [].slice.call(arguments)      return self.apply(context, outerArgs.concat(innerArgs))    }    return resultFn  }

23、深拷贝

1、递归:如果数据深度太深,会造成栈溢出

  const deepClone = (source) => {    const result = Array.isArray(source) ? [] : {}    for (let i in source) {      if (typeof source[i] == "object") {        result[i] = deepClone(source[i])      } else {        result[i] = source[i]      }    }    return result  }

2、循环:只是减少了数据广度,不会造成栈溢出

  function catchType(obj) {    const type = Object.prototype.toString.call(obj)    return type.substring(8, type.length - 1).toLowerCase()  }  function deepCloneStack(obj) {    const root = {}    const stack = [{      parent: root,      data: obj    }]    while (stack.length) {      const pop = stack.pop()      const {        parent,        data      } = pop      for (let i in data) {        if (data.hasOwnProperty(i)) {          if (catchType(data[i]) === "object") {            parent[i] = {}            stack.push({              parent: parent[i],              data: data[i]            })          } else if (catchType(data[i]) === "array") {            parent[i] = []            stack.push({              parent: parent[i],              data: data[i]            })          } else {            parent[i] = data[i]          }        }      }    }    return root  }

24、公布订阅模式

参考文档
参考文档

25、mvvm

参考文档

26、模仿map(),filter(),reduce(),some(),flag()

(1)模仿map

  Array.prototype.mapFn = function (fn, context) {    const arr = [].slice.call(this)    var result = []    for (var i = 0; i < arr.length; i++) {      result.push(fn.call(context, arr[i], i))    }    return result  };    Array.prototype.mapReduce = function (fn, context) {    const arr = [].slice.call(this)    return arr.reduce((prev, cur, index) => {      return [...prev, fn.call(context, cur, index)]    }, [])  };

(2)模仿filter

  Array.prototype.filterFn = function (fn, context) {    const arr = [].slice.call(this)    const result = []    for (var i = 0; i < arr.length; i++) {      fn.call(context, arr[i], i) && result.push(arr[i])    }    return result  }  Array.prototype.filterReduce = function (fn, context) {    const arr = [].slice.call(this)    return arr.reduce((prev, cur, index) => {      return fn.call(context, cur, index) ? [...prev, cur] : [...prev]    }, [])  };

(3)模仿some

  Array.prototype.someFn = function (fn, context) {    const arr = [].slice.call(this)    for (var i = 0; i < arr.length; i++) {      if (fn.call(context, arr[i], i)) return true    }    return false  }

(4)模仿reduce

  Array.prototype.reduceFn = function (fn, initial) {    const arr = [].slice.call(this)    let prev    let startIndex    if (initial == undefined) {      for (let i = 0; i < arr.length; i++) {        if (!arr.hasOwnProperty(i)) continue        startIndex = i        prev = arr[i]        break      }    } else {      prev = initial    }    for (let i = ++startIndex; i < arr.length; i++) {      prev = fn.call(null, prev, arr[i], i)    }    return prev  }

(5)模仿flat

  Array.prototype.flatFn = function (deep) {    const arr = [].slice.call(this)    if (deep == 0) return arr    return arr.reduce((prev, cur) => {      if (Array.isArray(cur)) {        return [...prev, ...[].flatFn.call(cur, deep - 1)]      } else {        return [...prev, cur]      }    }, [])  };

27、react相干

参考文档