具体内容能够查看笔记
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相干
参考文档