具体内容能够查看笔记
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) //true
a.__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 2
console.log(a.a, a.b); // undefined 2
console.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)instanceof
function A(){
if(this instanceof A){}
}
(2)new.target
function 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) //zhang
console.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= pro
console.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相干
参考文档
发表回复