万能的 JS(万字、基础、原理、面试、持续更新。。。)
万能的 JS
心无杂念,行路也将势如破竹。
- 万能的 JS
- JS(JavaScript 轻量级动态脚本语言)
- 面向对象思想:
- 作用域
- 预解释 (变量提声) 浏览器天生自带
- JS 中内存的分类
- JS 数据类型
- 检测数据类型
- 类型转换
- null 和 undefined 区别
- this 的指向(取什么值是在函数执行的时候决定的,不是在函数)
- 闭包
- call,apply 和 bind 区别
- ==和===区别:
- 深拷贝和浅拷贝
- 防抖和节流
- 数组
- 数组中常用的方法
- Math 数学方法
- String 字符串方法
- Date 日期 typeof Date -->”function”
- 类 Class
- 原型链
- new 的执行过程方
- 函数声明和函数表达式的区别:
- new Object()和 Object.create()区别:
- 继承
- 古代的继承
- ES6 发布订阅模式
- 事件
- 本地对象、内置对象、宿主对象(本全 E,内置不实例,宿主非本如 DOM)
- 页面加载
- ES6
- commonjs 和 es6 模块化的区别
- js 宏任务和微任务
- 异步和单线程
- js 操作 DOM
- Ajax (Asynchronous JavaScript And XML)
- 存储
- linux 命令:
- JS 中的垃圾
- JS 中捕获异常:
- RAF requestAnimationFrame
- 浏览器缓存:两个地方用到了缓存,DNS 缓存和页面资源缓存
- babel 编译原理
- 函数柯里化
JS(JavaScript 轻量级动态脚本语言)
JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式、声明式、函数式编程范式
- ECMAScript:语法规范,是 js 和 nodejs 要遵守的
- js 操作 dom,事件,发 ajax 请求 ==
ECMAScript + webAPI
- node 处理请求操作文件 ==
ECMAScript + nodeAPI
面向对象思想:
- 1.封装:保护成员、数据隐藏——方法、强制访问权限、便于理解
- 2.继承:重用代码、无需修改父类、*多重继承(组合)——JS 不支持、不好、*抽象类
- 3.多态:抽象、简化问题 (条件判断模拟多态)
作用域
-
1、全局作用域
- var 定义的全局变量不可以删除,没使用 var 定义的全局变量是 window 的属性存在,可删除
abcd=123,delete abcd =>true
- 函数内部没有用 var 定义的全局变量也是 window 的属性存在
- var 定义的全局变量不可以删除,没使用 var 定义的全局变量是 window 的属性存在,可删除
-
2、函数作用域
-
3、块状作用域 let&const
-
let 块级作用域
-
let 声明的全局变量不能用全局属性来访问。不会把变量定义到 window 上
-
let 不能重新定义
-
let 不会进行变量提升
-
const:常量,不可变的量,指针不能改,内容不可以改
// let的块级作用于 for (var i = 0; i < 3; i++) {setTimeout(function () {console.log(i);}, 1000); } // 3 3 3 用 let 就是 0 1 2// let没有预解释 console.log(a); var a = 1; // undefined let a = 1; // Cannot access 'a' before initialization 无法在初始化之前访问'a'// const不可变的量,指针不能改,内容不可以改 const a = 1; a = 2; // Uncaught TypeError: Assignment to constant variable. const b = [1]; b.push(2); console.log(b); // [1,2] Object.freeze(b); // =>彻底不能改 b.push(3); // Uncaught TypeError: Cannot add property 3, object is not extensible
-
-
4、动态作用域
预解释 (变量提声) 浏览器天生自带
当前的作用域中,js 代码执行之前,浏览器首先会默认把所有的带 var 和 function 的进行提前的声明或者定义
- 声明(declare):var num;告诉浏览器在全局作用域中有一个全局的变量了
- 定义(defined):num=12;给变量进行赋值,把数据变量联系在一起
-
var 和 function
- var 的变量提前声明但不会赋值(不定义),默认的值 undefined,当代码执行的时候才会赋值。
- function 提前声明并赋值(定义)
// 预解释只发生在当前的作用域下,例如:开始只对windows下的进行预解释,只有函数执行的时候才会对函数中的进行预解释console.log(num); //undefinedconsole.log(obj); //undefinedconsole.log(sum); //function本身var num=12; //赋值function sum(num1,num2){var total=num1+num2;}var obj={'name':'zqb',age:30}; //对象开辟一个空间,将属性名和属性值存进去*****************************console.log(haha); // 报错haha is not definedvar a =function(){}; //不会提前赋值,预解释只会看等号左边的变量,并不会看你的值是什么function (){ //当代码执行的时候,声明和赋值已经结束了,直接跳过function haha(){} //我们的预解释只发生在当前作用域*************}
-
加 var 和不加 var 的区别:(在全局作用域下)
- 1 是否被提前声明 (带 var 的提前声明,不带 var 的不预解释)
- 2 var 定义的全局变量不可以删除,没使用 var 定义的全局变量是 window 的属性存在,可删除
abcd=123,delete abcd =>true
-
函数的运行顺序:1 如果有形参是形参赋值 2 预解释 3 代码逐行执行。。
-
预解释的机制
- 1 不论条件是否成立都会预解释(if) chrome 下只声明
- 2 预解释的时候带 var 关键字的只看等号左边
- 3 全局作用域下的自执行函数不会预解释,预解释只发生在当前作用域
- 4return 后面的代码仍然会被预解释,但是 return 出来的值不会被预解释, 即使是一个函数也不会被预解释 ,后面代码不执行,return 后面的是返回值,return 下面预解释但不执行
- 5.当 var 和 function 的变量名字一样 不能重复声明了 但是重复赋值
//机制1 if ("num" in window) {//提前声明 num=undefinedvar num = 6; //给 num 赋值 } console.log(num); //6//机制2 var a = function () {}; sum(); //报错Uncaught ReferenceErrer:sum is not defined//机制3 console.log(b); //b is not defined !(function () {//自执行函数不会预解释var b = 0; })();//机制4 function fn() {console.log(num); //undefinedreturn function () {console.log(num);}; //return 后面的返回值不进行预解释alert(); //代码不执行var num = 9; //这个地方还会预解释,永远无法定义,因为代码走不到这里 } var f = fn(); //函数的执行 赋值是执行的结果 没有 return 就是 undefined fn();//机制5 var sum = 10; function sum() {} sum(); //不能执行 Uncaught TypeError: sum is not a function //第一步进行预解释 var sum =undefined;sum = 函数体 //第二步真正的赋值 var sum = 10foo(); //2 预解释先赋值 function foo() {console.log(1); } foo(); //2 var foo = "haha"; //原来的函数引用地址已经被破坏,并且 foo 赋值了一个字符串,让一个字符串去执行 foo(); //foo is not a function function foo() {console.log(2); //预解释的时候还会赋值 } foo(); //报错执行不到这里
JS 中内存的分类
- 栈内存:用来提供一个供 JS 代码执行的环境->作用域(全局作用域/私有作用域),基本数据类型都存在栈内存里
- 堆内存:用来存储引用数据类型的值->对象存储的是属性名和属性值,函数存储的是代码字符串…
JS 数据类型
- 基本数据类型:String,Number,Boolean,Null,Undefined,symbol。
值类型(不互相干扰)
- 引用数据类型:Object,Array,Function
引用类型(地址,相互改变有影响)
检测数据类型
-
typeof:优点:能够快速区分基本数据类型 缺点:不能将 Object、Array 和 Null 区分,都返回 object
-
instanceof:优点:能够区分 Array、Object 和 Function,适合用于判断自定义的类实例对象 缺点:Number,Boolean,String 基本数据类型不能判断。原理:判断实例对象的属性和构造函数的属性是不是引用的同一个地址
console.log(2 instanceof Number); // false console.log([] instanceof Array); // true
-
constructor 构造函数
-
Object.prototype.toString.call():优点:精准判断数据类型 缺点:写法繁琐不容易记,推荐进行封装后使用
var toString = Object.prototype.toString; console.log(toString.call(2)); //[object Number]
类型转换
- 强制类型转化:parseInt,parseFloat,toString
- 隐式类型转化:if,逻辑运算,==,+,拼接字符串
- 类型转化:字符串拼接,==,!!
false=='' //true
null==undefined //true
obj.a==null 相当于 obj.a===null||obj.a===undefined
const a = 0
!a //true
!!a //false
!!0 === false //true
!!NaN === false //true
!!null ===false //true
!!undefined === false //true
10&&0 //0
abc||'' //abc
// 面试题
var num = 20; //20*=3=60 通过地30行执行fn()把window.num *= 4l了240
var obj = {num: 30, //120fn: (function (num) {//num = 20this.num *= 3; //this=>window.num*=3==60;num += 20; //20+=20 = 40;//相当于当前作用域内的num变量修改成40了var num = 45; //因为和形参是相同的,所以不被预解释,这个var在此处有和没有是一样的效果 num = 45;return function () {this.num *= 4; //第30行执行的时候,this是window,window.num *=4==240;num += 20; //num+=20 =65console.log(num); //65};})(this.num), //this是谁window ==> window.num
};
var fn = obj.fn; //把obj.fn的引用地址告诉了fn
fn(); //65
obj.fn(); // 85 this是obj 所以this.num=30*4=120
console.log(window.num, obj.num); // 240 120
null 和 undefined 区别
- undefined 用法:
- 变量被声明了,但没有赋值时,就等于 undefined。
- 调用函数时,应该提供的参数没有提供,该参数等于 undefined。
- 对象没有赋值的属性,该属性的值为 undefined。
- 函数没有返回值时,默认返回 undefined。
- null 空指针,用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。用法:
- 作为函数的参数,表示该函数的参数不是对象。
- 作为对象原型链的终点。
this 的指向(取什么值是在函数执行的时候决定的,不是在函数)
- 1、对象的函数属性,点击事件,谁调用 this 就指向谁
- 2、构造函数中的 this 指向当前实例
- 3、函数中 this 指向 window,严格模式 this=>undefined
- 4、call,apply,bind 能改变 this 指向
fn.call(thisObj,p1,p2) === fn.apply(thisObj,[p1,p2]);
- 5、箭头函数的 this 取上级作用域的值
闭包
- 本质上说就是在函数内部和函数外部搭建起一座桥梁,使得子函数可以访问父函数中所有的局部变量,但是反之不可以,这只是闭包的作用之一,另一个作用,则是保护变量不受外界污染,使其一直存在内存中,在工作中我们还是少使用闭包的好,因为闭包太消耗内存,不到万不得已的时候尽量不使用。
// 闭包隐藏数据:只提供 API
function createCache() {const data = {}; // 闭包中的数据,被隐藏,不被外界访问return {set: function (key, val) {data[key] = val;},get: function (key) {return data[key];},};
}
const c = createCache();
c.set("a", 100);
console.log(c.get("a"));// let 块级作用域就解决了
let a;
for (let i = 0; i < 10; i++) {a = document.createElement("a");a.innerHTML = i + "<br>";a.addEventListener("click", function (e) {// 如果 i 是全局的点击的时候执行 i 已经变成 10 了e.preventDefault();alert(i);});document.body.appendChild(a);
}//闭包的影响:占用内存不释放,内存在函数执行后依次释放
let a = 0;
function fn1() {let a1 = 100;function fn2() {let a2 = 200;function fn3() {let a3 = 300;return a + a1 + a2 + a3;}fn3();}fn2();
}
fn1();
call,apply 和 bind 区别
- 作用都是将函数绑定到上下文中,用来改变函数中 this 的指向;不同点在于语法的不同。
- apply 和 call 的区别是:call 接受若干个参数,apply 第二个参数是数组,bind()方法创建一个新的函数, 当被调用时,将其 this 关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
sayName.call(callObj, "call param");
sayName.apply(applyObj, ["apply param"]);
let bindFn = sayName.bind(bindObj, "bind param");
bindFn();
-
call 接受的是若干个参数列表,方法的第一个参数:
- 1、如果是一个对象类型,那么函数内部的 this 指向该对象
- 2、如果是 undefined、null,那么函数内部的 this 指向 window
- 3、如果是数字,this 指向对应的 Number 构造函数的实例:1–> new Number(1);如果是字符串,this 指向 String 构造函数的实例"abc" --> new String(“abc”);如果是布尔值,this 指向 Boolean 构造函数的实例 false --> new Boolean(false)
-
apply 参数传数组,call 和 apply 不同的地方:传参的形式不同
function toString(a, b, c) {console.log(a + " " + b + " " + c); } toString.call(null, 1, 3, 5); //"1 3 5" toString.apply(null, [1, 3, 5]); //"1 3 5"
-
bind 不立即执行
var obj = {age: 18,run: function () {console.log(this); //this:objvar _that = this;setTimeout(function () {//this 指向 windowconsole.log(this.age); // undefinedconsole.log(_that.age); //18}, 50);},
};
obj.run();//bind 是 es5 中才有的(IE9+)
var obj5 = {age: 18,run: function () {console.log(this); //this:obj5setTimeout(function () {console.log(this.age);}.bind(this),50); //this:obj5//通过执行了 bind 方法,匿名函数本身并没有执行,只是改变了该函数内部的 this 的值,指向 obj5},
};
obj5.run();//bind 基本用法
function speed() {console.log(this.seconds);
}
//执行了 bind 方法之后,产生了一个新函数,这个新函数里面的逻辑和原来还是一样的,唯一的不同是 this 指向{ seconds:100 }
var speedBind = speed.bind({ seconds: 100 });
speedBind(); //100(function eat() {console.log(this.seconds);
}.bind({ seconds: 360 })()); //360// 模拟 bind
myBind = function () {const arr = Array.from(arguments); // 参数转为数组// const args = Array.prototype.slice.call(arguments);const t = args.shift(); // 拿出第一项thisconst self = this; // fn1.bind(...) 中的 fn1return function () {// 返回一个函数return self.apply(t, args);//return self.call(t, ...args)};
};
和=区别:
-
==, 两边值类型不同的时候,要先进行类型转换,再比较
-
===,不做类型转换,类型不同的一定不等。
==类型转换过程:
- 如果类型不同,进行类型转换
- 判断比较的是否是 null 或者是 undefined, 如果是, 返回 true .
- 判断两者类型是否为 string 和 number, 如果是, 将字符串转换成 number
- 判断其中一方是否为 boolean, 如果是, 将 boolean 转为 number 再进行判断
- 判断其中一方是否为 object 且另一方为 string、number 或者 symbol , 如果是, 将 object 转为原始类型再进行判断
经典面试题:[] == ![] 为什么是 true 转化步骤:
- !运算符优先级最高,![]会被转为为 false,因此表达式变成了:[] == false
- 根据上面第(4)条规则,如果有一方是 boolean,就把 boolean 转为 number,因此表达式变成了:[] == 0
- 根据上面第(5)条规则,把数组转为原始类型,调用数组的 toString()方法,[]转为空字符串,因此表达式变成了:’’ == 0
- 根据上面第(3)条规则,两边数据类型为 string 和 number,把空字符串转为 0,
因此表达式变成了:0 == 0 两边数据类型相同,0==0 为 true
深拷贝和浅拷贝
// 浅拷贝
function simpleClone(obj) {var result = {};for (var i in obj) {result[i] = obj[i];}return result;
}
// 深拷贝
function deepClone(obj = {}) {if (typeof obj !== "object" || obj == null) {return obj;} // obj 是 null ,或不是对象数组直接返回let result; // 初始化返回结果obj instanceof Array ? (result = []) : (result = {});for (let key in obj) {if (obj.hasOwnProperty(key)) {// 保证 key 不是原型的属性result[key] = deepClone(obj[key]); // 递归调用!!!}}return result; // 返回结果
}
防抖和节流
- 正常执行 llllllllllll llllll lllllllllllll
- 函数防抖 l l l
- 函数节流 l l l l l l l l l
-
防抖 (debounce)顾名思义,防止抖动,以免把一次事件误认为多次
- 场景:登录、发短信等按钮避免用户点击太快,导致发送了多次请求,
调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位
文本编辑器实时保存,当无任何更改操作一秒后进行保存 - 防抖重在清零 clearTimeout(timer)
function debounce(f, wait) {let timer;return (...args) => {if (timer) clearTimeout(timer);timer = setTimeout(() => {f(...args);}, wait);}; } function debounce(fn, delay) {let timer = null;return function () {if (timer) clearTimeout(timer);timer = setTimeout(() => {fn.apply(this, arguments);}, delay);}; }
- 场景:登录、发短信等按钮避免用户点击太快,导致发送了多次请求,
-
节流 (throttle) 控制水的流量。控制事件发生的频率,如控制为 1s 发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。
- 场景:scroll 事件,每隔一秒计算一次位置信息等
浏览器播放事件,每个一秒计算一次进度信息等
input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 - 节流重在加锁 timer=timeout
- 场景:scroll 事件,每隔一秒计算一次位置信息等
function throttle(f, wait) {let timer;return (...args) => {if (timer) {return;}timer = setTimeout(() => {f(...args);timer = null;}, wait);};
}
function throttle(fn, cycle) {let start = Date.now();let now;let timer;return function () {now = Date.now();clearTimeout(timer);if (now - start >= cycle) {fn.apply(this, arguments);start = now;} else {timer = setTimeout(() => {fn.apply(this, arguments);}, cycle);}};
}
- 总结:
- 防抖:防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零 clearTimeout。防抖可以比作等电梯,只要有一个人进来,就需要再等一会儿。业务场景有避免登录按钮多次点击的重复提交。
- 节流:控制流量,单位时间内事件只能触发一次,与服务器端的限流 (Rate Limit) 类似。代码实现重在开锁关锁 timer=timeout; timer=null。节流可以比作过红绿灯,每等一个红灯时间就可以过一批。
数组
-
ES5 中数组遍历的方法:
- for 循环:
break
直接跳出循环;continue
下边的代码不执行,执行下一个循环 - forEach()、every()、some()、for(let index in obj){}、filter()、fill()
for (var i = 1; i <= 10; i++) {if (i == 6) continue;console.log(i); } // 1234578910// forEach不支持 break 和 continue arr.forEach((item) => {console.log(item); });// every没有 return true 就只执行一次。 arr.every((item) => {console.log(item);return true; });// for in 支持 continue,索引是字符串,数组也是对象,数组也可以有属性 for (let index in obj) {console.log(index, obj[index]); }// every():一假即假 let arr = [12, 3, 4]; console.log(arr.every((item) => {return item > 3;}) ); //false// some():一真即真 let arr = [12, 3, 4]; console.log(arr.some((item) => {return item == 3;}) ); //true
- for 循环:
-
ES6
-
for of、Array.from()、flat(n)拍平 n 层、Array.of()、find()、findIndex()、copyWithin()、includes()、reduce()
//for of 遍历任何数据结构 for (let item of arr) {console.log(item); }//类数组转化数组: // es5: [].slice.call(document.querySelectorAll("img")); //nodeList 调用数组的方法 // es6: Array.from(arguments); Array.from({ length: 5 }, function () {return 1; });// flat:拍平数组 [1, [2, 3]].flat(2) //[1,2,3] [1, [2, 3, [4, 5]].flat(3) //[1,2,3,4,5] [1[2, 3, [4, 5[...]].flat(Infinity)//[1,2,3,4...n] // 实现flat function flat(arr) {const isDeep = arr.some((item) => item instanceof Array); // 查看数组层级if (!isDeep) {return arr; //已经是一层}const res = Array.prototype.concat.apply([], arr); //一层数组拍平return flat(res); // 递归 }// 去重: function unique(arr) {const res = [];arr.forEach((item) => {if (res.indexOf(item) < 0) {res.push(item);}});return res;//使用 set 去重://const set = new Set(arr)//return [...set] }//生成新数组 let array = Array(5); let array = []; //es6: Array.of(1, 2, 3, 4, 5); let array = Array(5).fill(1); //Array.fill(value,start,end),不限制全部填充替换//es5 查找一个元素 arr.filter(function (item) {return item === 6; }); //[6] 没有返回[ ],不高效,都查找一遍 //es6: arr.find(function (item) {return item === 6; }); // 6 只找到第一个值,没有 undefinedarr.findIndex(function(item){return item===6})arr.copyWithin(target[, start[, end]]) // target 0 为基底的索引,复制序列到该位置。如果是负数,target 将从末尾开始计算。 如果 target 大于等于 arr.length,将会不发生拷贝。如果 target 在 start 之后,复制的序列将被修改以符合 arr.length。 // start 0 为基底的索引,开始复制元素的起始位置。如果是负数,start 将从末尾开始计算。如果 start 被忽略,copyWithin 将会从0开始复制。 // end 0 为基底的索引,开始复制元素的结束位置。copyWithin 将会拷贝到该位置,但不包括 end 这个位置的元素。如果是负数, end 将从末尾开始计算。如果 end 被忽略,copyWithin 方法将会一直复制至数组结尾(默认为 arr.length)。 [].copyWithin(target,start,end) // 通过自身数据,在指定位置替换数据,返回改变后的数组。 [1, 2, 3, 4, 5].copyWithin(1, 0, 3) // [1, 1, 2, 3, 5]const array1 = [1, 2, 3]; console.log(array1.includes(2)); // true// reduce arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) // accumulator 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值 // currentValue 数组中正在处理的元素 // index 可选 数组中正在处理的当前元素的索引 // array可选 调用reduce()的数组 // initialValue可选 作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。 var flattened = [[0, 1], [2, 3], [4, 5]].reduce(( acc, cur ) => acc.concat(cur),[] ); // flattened is [0, 1, 2, 3, 4, 5]
-
数组中常用的方法
-
第一大部分:增删改查
方法 功能 参数 返回值 原数组 push 末尾添加 添加的项 添加后的数组长度 改变 pop 删除最后一项 无 删除的项 改变 unshift 开头添加一项 添加的项 添加后的数组长度 改变 shift 删除数组第一项 无 删除的项 改变 splice(n,m,x) 从索引 n 开始包含 n,删除 m 个元素,用 x 替换原来的 n 是索引,m 是个数,x 新增的替换内容 删除的项 改变 slice(n,m) 从索引 n 开始找到索引 m 不包含 m(查询复制) n 从索引 n 开始,m 到索引 m 查询数组项 不变 -
末尾添加 push:
ary.splice(ary.length,0,x); ary[ary.length]=10;
-
末尾删除 pop:
ary.splice(ary.length-1); ary.length--;
-
开头添加 unshift:
splice(0,0,x)
-
开头删除 shift:
splice(0,1)
-
ary.splice(n);从索引 n 开始,删除到数组末尾
-
ary.splice(0);清空数组,返回一个新克隆的数组
-
ary.splice();一项都没有删除,返回空数组
-
splice(n,m,x):先删除,让后用 x 替换,从索引 n 开始 删除 m 个元素用 x 替换原来的,返回删除的内容数组,原有数组改变
-
splice(n,0,x)添加新的内容,从索引 n 开始删除 0 个内容,把新增加的内容放在索引 n 的前面,返回的结果是空数组,原有数组改变
-
slice(n,m)从索引 n 开始找到索引为 m 处,不包含 m,返回新数组,原数组不变
-
slice(n)从索引 n 开始一直找到数组末尾,
n为负数,从右往左复制,m为负数,从右边往左减m个
-
slice(0) / slice() 把原来的数组克隆一份新数组返回,不修改原数组
let arr = [1, 2, 3, 4, 5, 6]; console.log(arr.slice(-5, -2)); //[2,3,4]
-
-
第二大部分: 数组的截取和拼接
方法 功能 参数 返回值 原数组 concat 拼接数组 要拼接的数组 拼接后的数组 不变 join 拼接数组 要拼接的数组 拼接后的数组 不变 toString 数组转化字符串 无 转化好的字符串 不变 ary1.concat(ary2); // 把 ary2 和 ary1 进行拼接,ary2 在后面 // 相当于把 ary1 克隆了一份 ary1.concat(); ary1.concat([]);//扩展:eval:js 中,把字符串变成表达式执行的方法 var ary = [1, 2, 3, 4, 5, 6]; console.log(eval(ary.join("+"))); //21
-
第三大类:排序
方法 功能 参数 返回值 原数组 reverse 倒序数组 无 倒序后的数组 改变 sort 按一定规则排序 函数 排序好的 改变 ary.sort(); // 这样只能处理 10 以内的数字进行排序,因为按照 UNICODE 编码的值排序 ary.sort((a, b) => a - b); // 由小到大排列 ary.sort((a, b) => b - a); // 由大到小排列
-
第四大类 ie678 不兼容的
-
indexOf / lastIndexOf (字符串这个两个方法兼容所有浏览器,而数组是不兼容的),数组中第一次/最后一次出现位置的索引,
没有返回-1
,有就返回索引值
,原来数组不变
-
forEach / map 都是用来遍历数组中的每一项的,forEach 返回值是 undefined,map 返回一个新数组
// map 和 forEach 的语法一样,forEach 返回值是 undefined,map 返回一个新数组 /*@params arr 可选。当前元素所属的数组对象。thisArg 可选。如果 thisArg 参数有值,则每次 callback 函数被调用时,this 都会指向 thisArg 参数。如果这个参数为空, "undefined" 会传递给 "this" 值*/ array.forEach(function(currentValue, index, arr), thisArg) arr.map(function callback(currentValue, index, array) { // Return element for new_array }, thisArg)ary.forEach(function (item, index) {}); // 原数组不变 返回的新数组是每一项都乘以 10 ary.map(function (item, index) {return item * 10; }); console.log(ary);
-
Math 数学方法
- Math.abs(); //绝对值
- Math.pow(2,3); //平方 2 底数 3 指数 放大镜
- Math.sqrt(); //开平方 放大镜
- Math.ceil(); //向上去整
- Math.floor(); //向下取整
- Math.round(); //四舍五入 负数需要特殊记忆下 向地板靠拢
- Math.max(); //取最大值 是一组数 不是数组
- Math.min(); //取最小值
- Math.random(); //获取从 0 到 1 之间的随机数 [0,1)
- Math.round(Math.random()*(m-n)+n); //获取从 n 到 m 的随机整数 (大-小)
String 字符串方法
- charAt 通过指定的索引值获取字符 ,参数是索引值,返回值就是获取到的字符(验证码)
- charCodeAt 通过索引值获取指定字符的 ASCII 码值
- substr(n,m) 截取:从索引 n 截取 m 个,只有一个参数默认截取到末尾,字符串不变
- subtring(n,m) 复制:索引 n 复制到索引 m 不包含 m,只有一个参数截取到末尾
- slice 跟 substring 是一样的,不同点:slice 支持负数索引,
- toUpperCase 转变成大写
- toLowerCase 转换成小写
- indexOf 字符出现在字符串中的索引位置,如果有返回对应索引,没有返回-1
- lastIndexOf 同 indexOf,最后一次出现的位置的索引 数组不兼容,字符串方法兼容
- split 把字符串按照指定的分隔符拆分成数组
- localCompare;字符串和字符串比较,把两个字符串转化拼音比较字母顺序,值-1,1,0.
- replace(被替换,用谁替换) 替换字符串 后面可以接函数 只替换一次,
/a/g 全局匹配
let str = 'dfgfgdfg'; console.log(str.replace(/df/g, '666')); //666gfg666g
- match --正则时候讲
- endsWith() 以 xxx 结尾
- startsWith() 以 xxx 开头
- includes() 包含 xxx
- concat 字符串拼接
- padEnd()/padStart() 填充字符串,补白
- trim()
- trimEnd()
- trimStart()
- concat 字符串拼接
let greetList = ["Hello", " ", "Venkat", "!"]; "".concat(...greetList); // "Hello Venkat!"
Date 日期 typeof Date -->”function”
Date 时间: new Date(); 参数:转换成一个时间格式的对象
console.log(new Date()); //2020-04-29T06:39:49.605Z
console.log(date.getFullYear()); //年
console.log(date.getYear()); //年 1900 年开始算
console.log(date1.getMonth()); //月份比实际月份小 1 [0,11]
console.log(date.getDate()); //日期 1-31
console.log(date.getDay()); // [1,2,3,4,5,6,0] 星期日是 0
console.log(date.getHours()); //小时
console.log(date.getMinutes()); //分
console.log(date.getSeconds()); //秒
console.log(date.getMilliseconds()); //ms 毫秒
console.log(date.getTime()); //这个时间对象距离 1970 年 1 月 1 日 0 点 0 分 0 秒
- ES9 For await of :异步集合遍历
类 Class
// ES5:
let Animal = function (type) {this.type = type; //私有属性this.eat = function () {}; //私有方法
};
Animal.prototype.eat = function () {}; //公共方法,原型链集成
Animal.walk = function () {}; //es5类的静态方法
let dog = new Animal("dog");
dog.constructor.prototype.eat = function () {}; //修改类的原型方法// ES6:
class Animal {constructor(type) {//构造函数里写属性,构造函数外写方法this.type = type;}eat() {} //公有方法,原型上的方法// es6属性保护get age() {return _age;} //设置age属性 dog.age age就是一个入口set age(val) {if (val > 4) {// 通过set做拦截_age = val;}}static walk() {} //静态方法:拿不到类的实例对象
}
dog.age = 3; // 4 被set拦截没有生效// 类的实例方法:在原型上或者this.eat私有方法// es6定义私有方法
class Widget {foo(name) {setName.call(this, name);}
}
function setName(name) {return (this.name = name);
}
原型链
- 类:prototype 显示原型
- 实例:proto 隐式原型
-
1 创建构造函数/类时
- 天生自带一个 prototype 的属性。
- prototype 的值是一个对象类型(装的就是我们公有的属性)
console.log(Person.prototype);//Person {}
- prototype 的值也有一个天生自带的属性叫 constructor 构造器,并且这个属性的值是函数(构造函数,类)本身
console.log(Person.prototype.constructor);//[Function: Person]
//所有的对象都是Object的实例 (Object叫我们的基类) console.log(Person.prototype.__proto__); //{} console.log(Person.prototype.__proto__ == Object.prototype); //true Object也是函数
构造函数,类 ——> prototype(值:对象类型) ——> constructor(值:构造函数,类)本身
-
2 每个实例都是对象,都有proto属性,它是这个实例所属类的原型.
console.dir(person.__proto__==Person.prototype);//true
实例.proto ——>类.prototype
-
3 每个引用类型都有天生自带的属性proto,所以 prototype 的值也有天生自带一个proto的属性。并且这个属性的值也是一个对象类型,一直到我们的基类 Object
实例.proto ——>类.prototype.proto ——>Object.prototype
-
4 通过类的原型添加的属性和方法都是公有的,每个实例都会自带
-
5 一个实例的方法在运行的时候,如果这个方法是自己私有的,那么就直接用,如果不是私有的,那么通过proto去所属类的原型上去查找,如果还没有就通过原型的proto一直查到基类的 Object.如果还没有报错,如果有就直接用了。我们把这种通过proto查找的机制叫做原型链。
- 实例.proto === 原型
- 原型.constructor === 构造函数
- 构造函数.prototype === 原型
- 实例.constructor === 构造函数
var A = function () {};
var a = new A();
console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
console.log(a.__proto__.constructor); //[Function: A]`(function A 本身)
console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
console.log(a.__proto__.__proto__.__proto__); //null
//Object上有 hasOwnProperty isPrototypeOf propertyIsEnumerableclass jQuery {constructor(selector) {const result = document.querySelectorAll(selector);const length = result.length;for (let i = 0; i < length; i++) {this[i] = result[i];}this.length = length;this.selector = selector;}get(index) {return this[index];}each(fn) {for (let i = 0; i < this.length; i++) {const elem = this[i];fn(elem);}}on(type, fn) {return this.each((elem) => {elem.addEventListener(type, fn, false);});} // 扩展很多 DOM API
}// 插件
jQuery.prototype.dialog = function (info) {alert(info);
};// “造轮子”
class myJQuery extends jQuery {constructor(selector) {super(selector);} // 扩展自己的方法addClass(className) {}style(data) {}
}
new 的执行过程方
let newMethod = function (Parent, ...rest) {// 1.以构造器的prototype属性为原型,创建新对象;let child = Object.create(Parent.prototype);// 2.将this和调用参数传给构造器执行let result = Parent.apply(child, rest);// 3.如果构造器没有手动返回对象,则返回第一步的对象return typeof result === "object" ? result : child;
};
函数声明和函数表达式的区别:
- 函数声明 function fn(){} // 代码执行前会预加载
- 函数表达式 const fn = function(){} // 不会预加载
new Object()和 Object.create()区别:
- {}等同于 new Object(),原型 Object.prototype
- Object.create(null) 没有原型 Object.create({…}) 可指定原型
const obj2 = new Object(obj1); // obj1===obj2 true 全相等的
const obj2 = Object.create(obj1); // obj1===obj2 false 会把obj1的方法都放到obj2的原型上
继承
let Dog = function () {Animal.call(this, "dog"); // 初始化父类的构造函数并传参,获取父级的私有方法// A.apply(this, arguments);this.run = function () {}; //子类的私有方法
};
Dog.prototype = Animal.prototype; //引用同一个内存地址class Dog extends Animal {construtor(type) {//显示 隐式super(type); // 要和父类的 construtor 参数一样,super 要写在 this 上边this.age = 2;}
}//构造函数创建类
//function User (name,age){ this.name=name;this.age=age; }
class User {constructor(name, age) {//私有方法this.name = name;this.age = age;}//静态方法:不需要实例化类就能使用的方法static getOne() {return 111;}//原型方法//User.prototype.changeInfo=function(name,age){//this.name=name;//this.age=age;//}changeInfo(name, age) {this.name = name;this.age = age;}Info() {return this.name + ":" + this.age;}
}//子类继承
class Manger extends User {constructor(name, age, password) {super(name, age); //先创建父对象的属性,再添加给子类this.password = password;}changePassword() {this.password = password; //添加新方法}Info() {var info = super.info();return info + "--new";}
}
古代的继承
// 1原型链继承 父(公有+私有)==>子(公有) 无法向父类构造函数传参
B.prototype = new A(); //缺点:一个实例修改方法所有实例的方法都修改了
B.prototype.constructor = B; //由于修改了B的原型导致自带constructor属性丢失// 2 call 继承 父(私有)==>子(私有) 可以向父类传递参数
function B() {A.call(this);
} //把A函数中的this修改成b的当前实例,然后执行A。// 3拷贝继承 父(公有+私有)==>子(私有) 效率较低,内存占用高,for in不可枚举方法拿不到
//for in 遍历可以遍历实例的私有属性,也可以遍历人为添加的公有属性
function B() {var obj = new A(); //A的实例for (var key in obj) {this[key] = obj[key]; //把父类实例的所有属性和方法同时赋值给b一份}obj = null;
}// 4混合继承 原型+call 可以向父类传递参数 红色最完美的继承
B.prototype = new A() || A.prototype || Object.create(A.prototype);
//把A的私有的和公有的都变成B的公有的
B.prototype.constructor = B; //补全constructor属性
function B() {A.call(this);
} //call继承 把A的私有属性变成B的私有属性
ES6 发布订阅模式
class EventEmiter {constructor() {this._events = {}; //维护一个对象}on(eventName, callback) {if (this._events[eventName]) {//如果有就放一个新的this._events[eventName].push(callback);} else {//如果没有就创建一个数组this._events[eventName] = [callback];}}emit(eventName, ...rest) {if (this._events[eventName]) {//循环一次执行this._events[eventName].forEach((item) => {item.apply(this, rest);});}}removeListener(eventName, callback) {if (this._events[eventName]) {//当前数组和传递过来的 callback 相等则移除掉this._events[eventName] = this._events[eventName].filter((item) => item !== callback);}}once(eventName, callback) {function one() {//在 one 函数运行原来的函数,只有将 one 清空callback.apply(this, arguments);this.removeListener(eventName, one); //先绑定 执行后再删除}this.on(eventName, one); //emit 触发会执行此函数,会给这个函数传递 rest 参数}
}
class Man extends EventEmiter {}
let man = new Man();
function findGirl() {console.log("找新的女朋友");
}
function saveMoney() {console.log("省钱");console.log("arguments" + JSON.stringify(arguments));
}
// man.once('失恋', findGirl);
// man.on('失恋', findGirl) //失恋 ,绑定一个函数方法
man.on("失恋", saveMoney); //失恋 ,绑定一个函数方法
// man.removeListener('失恋', saveMoney); //移除一个函数方法
事件
- 捕获和冒泡:事件捕获是为了逐层确定事件的来源,事件冒泡是为了逐级响应事件
- 在 ie 中,document.getElementById("#test").attachEvent(type,listener);
detachEvent(event,function);
function bindEvent(elem, type, fn) {elem.addEventListener(type.fn);
}
bindEvent(btn1, "click", (event) => {console.log(event.target); //获取触发的元素event.preventDefault(); //阻止默认行为alert("clicked");
});
// 阻止事件冒泡:e.stopPropagation()
// 事件代理:利用事件冒泡把事件绑定到父级元素上,通过判断event.target.nodeName==='A'来进行操作
function bindEvent(elem, type, selector, fn) {if (fn == null) {fn = selector;selector = null;}elem.addEventListener(type, (event) => {const target = event.target;if (selector) {//有代理绑定if (target.matches(selector)) {fn.call(target.event);}} else {//普通绑定fn.call(target, event);}});
}
本地对象、内置对象、宿主对象(本全 E,内置不实例,宿主非本如 DOM)
- 本地对象:ECMAScript 提供的对象,包括 Array Object RegExp 等可以 new 实例化的对象和 Math 等不可以实例化的
- 内置对象:Gload,Math 等不可以实例化的(他们也是本地对象,内置对象是本地对象的一个子集)
- 宿主对象:所有的非本地对象,所有的 BOM 和 DOM 对象都是宿主对象,如浏览器自带的 document,window 等对象
页面加载
- onready 是页面解析完成之后执行,而 onload 是在页面所有元素加载完成后执行
- DOM 加载到 link 标签 css 文件的加载是与 DOM 的加载并行的,也就是说,css 在加载时 Dom 还在继续加载构建,而过程中遇到的 css 样式或者 img,则会向服务器发送一个请求,待资源返回后,将其添加到 dom 中的相对应位置中;
- 在 script 标签中添加 defer=“ture”,则会让 js 与 DOM 并行加载,待页面加载完成后再执行 js 文件,这样则不存在阻塞;
- 在 scirpt 标签中添加 async=“ture”,这个属性告诉浏览器该 js 文件是异步加载执行的,也就是不依赖于其他 js 和 css,也就是说无法保证 js 文件的加载顺序,但是同样有与 DOM 并行加载的效果;
同时使用 defer 和 async 属性时,defer 属性会失效; - 可以将 scirpt 标签放在 body 标签之后,这样就不会出现加载的冲突了。
ES6
-
默认值
function f(x, y = 2, z = 4) {} f(1, undefined, 11); //y传undefined是默认值2function f(x, y = 9, z = x + y) {console.log(Array.from(arguments)); //拿到传的参数console.log(f.length); //直接拿函数的length,能获取到没有默认值的参数的个数 }
-
Rest parameter 参数
function sum(base, ...nums) {let num = 0;nums.forEach(function (item) {num += item * 1;});return base * 2 + num;
}
-
spread 操作
sum(...data)
-
箭头函数
-
什么时候不能使用箭头函数
// 定义对象的方法 const calculator = {array: [1, 2, 3],sum: () => {console.log(this === window); // => truereturn this.array.reduce((result, item) => result + item);}, }; console.log(this === window); // => true // Throws "TypeError: Cannot read property 'reduce' of undefined" calculator.sum();// 定义事件回调函数 const button = document.getElementById("myButton"); button.addEventListener("click", () => {console.log(this === window); // => truethis.innerHTML = "Clicked button"; });// 定义原型的方法 function Cat(name) {this.name = name; } Cat.prototype.sayCatName = () => {console.log(this === window); // => truereturn this.name; }; const cat = new Cat("Mew"); cat.sayCatName(); // => undefined// 定义构造函数不能用箭头函数 const Message = (text) => {this.text = text; }; // Throws "TypeError: Message is not a constructor" const helloMessage = new Message("Hello World!");
-
-
Set 数据结构:不能重复数据,数据是可遍历的对象
let s = new Set([1, 2, 3]); s.add(1).add(2); s.delete(1); s.clear(); //清空 s.has(1); //true s.size; s.keys(); s.values(); s.entries(); //返回键值对 s.forEach(function (item) {}); for (let item of s) {console.log(item); }// set去重数组,牛逼! let newArr = [...new Set(arr)];
-
Map 数据结构:key 可以是任意值,可以是对象或者函数
let map = new Map([[1, 2],[3, 4], ]);map.set(2, 1); map.delete(1); // 删除key map.clear(); map.size; map.has(1); // 查索引对应的值 map.get(1); map.keys(); map.values(); map.entries(); map.forEach((value, key) => {}); for (let [key, value] of map) { } //可遍历的对象才能用for of
-
WeakSet:只能存对象
-
WeakMap:只能是对象类型的key
-
object
// 可以写变量或表达式 obj = { x, y, [z]: 6 }; obj = {x, y, [x + z] };const target = {};const source = {b:3,a:4}; // 相同的属性被覆盖,不同的属性被拷贝 Object.assign(target,source) // es6数据拷贝(浅)引用类型的地址进行替换,不会精确到差异 Object.is(); // 两个值是否相等 Object.is(NaN,NaN);// true NaN===NaN F Object.is({},{});// false {}==={} F Object.is(+0,-0);// false +0===-0 T// Object.is() 会在下面这些情况下认为两个值是相同的: // 两个值都是 undefined // 两个值都是 null // 两个值都是 true 或者都是 false // 两个值是由相同个数的字符按照相同的顺序组成的字符串 // 两个值指向同一个对象 // 两个值都是数字并且 // 都是正零 +0 // 都是负零 -0 // 都是 NaN // 都是除零和 NaN 外的其它同一个数字
-
Template:模板字符串
-
解构赋值
let arr = [1, 2]; let [a, b] = arr; let [a, , b] = arr; // 略过某一项用,, let [a, , b] = new Set([1, 2, 3]);// 解构赋值不仅可以赋值变量,还可以赋值对象的属性 let user = ({ name: "s", username: "d" }; [user.name, user.username] = [1, 2]; for (let [k, v] of Object.entries(user)) {console.log(k, v);//[ [ 'name', 1 ], [ 'username', 2 ] ] } let [user, name, ...last] = arr; //1,2,[3,4,5]// 多维数组解构 let arr = [1,[2,3],4]; let [a,[b,c],d]=arr;// 不完全解析 let [a,[,c],d]=arr;// 变量交换 let x = 1,y=2; [y,x]=[x,y]// Set解构赋值 let [x,y] = new Set([1,2]) // x:1,y:2let [x,...y,6] = [1,2,3,4,5,6] // Rest element must be last element let [x,...y] = [1,2,3,4,5,6] // y:[2,3,4,5,6]// 对象的解构赋值 let {name} = {name:'Q',age:21} console.log(name) // Q// 嵌套解构:模式不能打印,只有变量能打印 let obj = {a:{b:{c:3}}}; // a,b是模式,只有c是变量能打印 let {a:{b:{c}}} = obj console.log(c); // 3// 默认值 let [x=1,y]=[undefined,2] // x:1,y:2// 修改变量名 let {name:myName} = obj console.log(myName)// 字符串 let [a,b,c] = 'hello' // a:h b:e c:o// 参数是数组 function test([x=1,y=2]=[],z=3){console.log(x,y,z) } test([],80)
-
Promise
function loadScript(src) {// pending,undefinedreturn new Promise((resolve, reject) => {let script = document.createElement("script");script.src = src;script.onload = () => resolve(src); // fulfilled,resultscript.onerror = (err) => reject(err); // rejected,errordocument.head.append(script);});
}
loadScript("./1.js").then(loadScript("./2.js")).then(loadScript("./3.js"));
// .then是promise对象原型上的方法,每次返回一个promise实例,需要传递两个参数,如果没传返回一个空的promise对象,保证可以继续调用.then方法
// promise.then(onFulfilled,onRejected)loadScript("./1.js").then(() => {return loadScript("./4.js");},(err) => {console.log(err);}).then(() => {loadScript("./3.js");},(err) => {console.log(err);});// promise的静态方法
Promise.resolve(42); // 包裹返回的静态值可以调用then方法
Promise.reject(new Error("ss"));
// catch也是实例的方法 catch异常处理.then().catch(err=>console.log(err))//异步的并行
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(20);
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then((value) => {console.log(value);
});
Promise.race(); //先到先得
const p1 = () => {return new Promise((resolve, reject) => {setTimeout(function () {resolve(1);}, 1000);});
};
const p2 = () => {return new Promise((resolve, reject) => {setTimeout(function () {resolve(2);}, 3000);});
};
Promise.race([p1(), p2()]).then((value) => {console.log(value);
});//Promise代码:
const callAsync = (() => {let pending = false;let count = 1;let textNode = document.createTextNode(count);let tasks = [];let nextTickHandler = () => {pending = false;let cbs = tasks.slice(0);tasks = [];cbs.forEach((cb) => cb());};let observer = new MutationObserver(nextTickHandler);observer.observe(textNode, {characterData: true,});let nextTick = () => {count = (count + 1) & 1;textNode.data = count;};return (fn, args, cb, onError) => {let func = () => {try {cb ? cb(fn(args)) : fn(args);} catch (err) {onError(err);}};tasks.push(func);if (pending) return;pending = true;nextTick();};
})();const PENDING = "pending",FULFILLED = "fulfilled",REJECTED = "rejected",isFunction = (fn) => typeof fn === "function";class MyPromise {constructor(fn) {//接收一个excutor执行函数为参数, excutor有两个参数resolve rejectthis._status = PENDING; //初始状态this._onFulfilledQueue = []; // 存储fulfilled状态对应的onFulfilled函数this._onRejectedQueue = []; // 存储rejected状态对应的onRejected函数this._value = null; // fulfilled状态时 返回的信息this[Symbol.toStringTag] = "MyPromise";try {fn(this._resolve.bind(this), this._reject.bind(this)); //立即执行excutor} catch (err) {this._reject(err);}}_resolve(value) {//成功状态下接收的值if (this._status !== PENDING) return;this._status = FULFILLED;const runFulfilled = (value) => {let fn;while ((fn = this._onFulfilledQueue.shift())) fn(value);};const runRejected = (error) => {let fn;while ((fn = this._onRejectedQueue.shift())) fn(error);};if (value instanceof MyPromise) {value.then((res) => {this._value = res;runFulfilled(res);},(err) => {this._value = err;runRejected(err);});} else {this._value = value;runFulfilled(value);}}_reject(error) {//接收失败的原因if (this._status !== PENDING) return;this._status = REJECTED;this._value = error;let fn;while ((fn = this._onRejectedQueue.shift())) fn(error);}then(onFulfilled, onRejected) {//onFulfilled接收成功的值,onRejected接收失败的原因onFulfilled = isFunction(onFulfilled) ? onFulfilled : (res) => res; //resolve(成功) onFulfilled调用onRejected = isFunction(onRejected)? onRejected: (err) => {throw err;}; //reject(失败)return new MyPromise((onFulfilledNext, onRejectedNext) => {const resolve = (value) => {callAsync(onFulfilled,value,(res) => {if (res instanceof MyPromise) {res.then(onFulfilledNext, onRejectedNext);} else {onFulfilledNext(res);}},onRejectedNext);};const reject = (error) => {callAsync(onRejected,error,(res) => {if (res instanceof MyPromise) {res.then(onFulfilledNext, onRejectedNext);} else {onFulfilledNext(res);}},onRejectedNext);};switch (this._status) {case PENDING:this._onFulfilledQueue.push(resolve);this._onRejectedQueue.push(reject);break;case FULFILLED:resolve(this._value);break;case REJECTED:reject(this._value);break;}});}catch(onRejected) {//在链式写法中可以捕获前面then中发送的异常return this.then(null, onRejected);}static resolve(value) {return value instanceof MyPromise? value: value && isFunction(value.then)? new MyPromise((res) => res()).then(() => new MyPromise(value.then)): new MyPromise((res) => res(value));}static reject(error) {return new MyPromise((resolve, reject) => reject(error));}static all(list) {return new MyPromise((resolve, reject) => {let values = [],count = list.length;list.forEach((item, index) => {MyPromise.resolve(item).then((res) => {values[index] = res;--count == 0 && resolve(values);}, reject);});});}static race(list) {return new MyPromise((resolve, reject) => {list.forEach((item) => MyPromise.resolve(item).then(resolve, reject));});}static allSettled(list) {return new MyPromise((resolve) => {let count = list.length,values = [];list.forEach((item, index) => {MyPromise.resolve(item).then((value) => {values[index] = {status: "fulfilled",value,};--count == 0 && resolve(values);},(reason) => {values[index] = {status: "rejected",reason,};--count == 0 && resolve(values);});});});}finally(cb) {return this.then((value) => MyPromise.resolve(cb()).then(() => value),(reason) =>MyPromise.resolve(cb()).then(() => {throw reason;}));}
}
-
Reflect 反射机制:非反射先指定方法,反射是执行过程中根据条件选调用那个方法
是一个内置的对象,它提供拦截 JavaScript 操作的方法
const obj = { name: "abc", age: 18 }; // 旧: "name" in obj ? true : false; delete obj[age]; Object.keys(obj);Reflect.has(obj, "name"); Reflect.deleteProperty(obj, "age"); Reflect.ownKeys(obj); console.log(Reflect.apply(Math.floor, null, [4.72])); console.log(Reflect.apply(price > 100 ? Math.floor : Math.ceil, null, [price]) ); let d = Reflect.construct(Date, []); console.log(d.getTime(), d instanceof Date); const student = {}; const r = Reflect.defineProperty(student, "name", { value: "Mike2" }); console.log(student, r); const obj = { x: 1, y: 2 }; Reflect.deleteProperty(obj, "x"); console.log(obj); console.log(Reflect.get(obj, "x")); console.log(Reflect.get([3, 4], 1)); //4 console.log(Object.getOwnPropertyDescriptor(obj, "y")); let d = new Date(); console.log(Reflect.getPrototypeOf(d)); //看原型上的方法 console.log(Reflect.has(obj, "y")); Object.freeze(obj); //使obj不可以扩展 console.log(Reflect.isExtensible(obj)); //是不是可扩展的 // 自身的属性 console.log(Reflect.ownKeys(obj)); console.log(Reflect.ownKeys([1, 2])); //返回索引和length Reflect.preventExtensions(obj); //禁止扩展 Reflect.set(obj, "z", 4); Reflect.set(arr, 2, "goose"); Reflect.setPrototypeOf(arr, String.prototype); //修改原型对象
-
Proxy 代理
// Proxy保护原始信息 let o = {name: 'xiaomi',price: 1999 } let d = new Proxy(o, {get (target, key) {if (key === 'price') {return target[key] + 20} else {return target[key]}}set (target, key, value) {return false} }) console.log(d.price, d.name)// es5拦截处理 for (let [key] of Object.entries(o)) {Object.defineProperty(o, key, {writable: false}) }// 监听错误 window.addEventListener('error', (e) => {console.log(e.message)// report('./') }, true)
-
Symbol:不会重复的值
let name1 = Symbol("name"); let name2 = Symbol("name"); console.log(name1 === name2); // falseconst name = Symbol(); const person = {[name]: "abc",say() {console.log(this[name]);}, }; person[name]; // 'abc' Symbol.for(); // 内部接收字符串 Symbol.for(true)===Symbol.for('true') // √
-
遍历器 iterator 调用 next()方法才能继续执行
let arr = ["a", "b", "c"]; let iterator = arr[Symbol.iterator()]; console.log(iterator.next()); // {value:'a',done:false} console.log(iterator.next()); // {value:'b',done:false} console.log(iterator.next()); // {value:'c',done:false} console.log(iterator.next()); // {value:undefined,done:true} console.log(iterator.next()); // {value:undefined,done:true}
-
Generator 生成器 带*的 fn
- 带有*的函数
- 函数内部使用 yield 暂停执行,遇到 yield 执行就停下来了,yield 后的值作为 next 的 value
- 调用时用 next()恢复函数执行,找函数中的 yield 或者结尾函数暂停
function * fn(){console.log('foo');returen 'bar' } // 生成器执行生成一个iterator let it = fn() let res = it.next() console.log(res)// generator中使用yield分段执行: function * fn(){yield 1;yield 2;yield 3; } let it = fn; console.log(it.next()) // {value:1,done:false} console.log(it.next()) // {value:2,done:false} console.log(it.next()) // {value:3,done:false} console.log(it.next()) // {value:undefined,done:true}for (let v of it){console.log(v) } //1 2 3 只会打印done为false的值function * loop () {for (let i = 0; i < 5; i++) {yield console.log(i) //yield关键词} } const l = loop() // 场景:抽奖 一个一个抽/自定义遍历器 l.next() 0 l.next() 1 l.next() 2 l.next() 3 l.next() 4 l.next()function * gen () {let valval = yield 1console.log(val) } const l = gen() l.next() // 遇到 yield 执行停下来了 后边是 1 所以不打印 l.next() //undefined 函数已经结束还没找到 yield,yield 表达式没有值返回 undefinedfunction * gen () {let valval = yield * [1, 2, 3] //加\*说明后边是一个可遍历的对象console.log(val) } // next():返回当前数据的 value 和是否结束{value:1,done:false} l.next(10) console.log(l.return(100)) //return 提前结束{value:100,done:true} l.next(20) // 20 通过 next 传值 修改 yield 的返回值function * gen () {while (true) {try {yield 1} catch (e) {console.log(e.message)}} } const g = gen() console.log(g.next()) console.log(g.next()) console.log(g.next()) console.log(g.next()) g.throw(new Error('ss')) //继续执行不会影响类似 continue console.log(g.next())
-
Module:模块化设计
// 导出 export const name = 'hello' export let addr = 'Beijing' export var list = [1, 2, 3] // 导入 import { name, addr, list } from './name.js'// 一起导出 export default name export {addr,list } import name, { addr, list } from './name.js'// 导入改名:默认导出可以直接改名字,{}导出要用as改名 import name2, { addr as addr2, list } from './name.js'// 函数导出 const say = (content) => {console.log(content) } const run = () => {console.log('i am running') } //引入函数 import { say, run } from './say.js'export default say export {run } //默认导出放到花括号外 import say { run } from './say.js'// 默认导出对象 export default {code:1,message:'success' } import obj form './obj.js'// 导出多个对象: const data = {code: 1,message: 'success' } const des = {age: 20,addr: 'Beijing' } export default {data,des } import obj from './data.js' let {data, des} = obj//类的默认导出 export class Test {constructor () {this.id = 6} } export class Animal {constructor () {this.name = 'dog'} } export default class People {constructor () {this.id = '132'} } import { Test, Animal }form './test.js'// 导入全部模块起一个别名 import * as Mod from './mod' let test = new Mod.Test() console.log(test.id) let animal = new Mod.Animal() console.log(animal.name) let people = new Mod.default() console.log(people.id)
-
ES8:async await
-
ES9:For await of :异步集合遍历、Promise.finally()
function Gen(time) {return new Promise((resolve, reject) => {setTimeout(function () {resolve(time);}, time);}); } async function test() {let arr = [Gen(2000), Gen(100), Gen(3000)]; //都是异步操作for (let item of arr) {console.log(Date.now(), await item.then(console.log));} }async function test() {let arr = [Gen(2000), Gen(100), Gen(3000)];for await (let item of arr) {console.log(Date.now(), item);} }
-
ES9 中 Object 的 Rest 和 Spread
const output = {...input, // spread是拷贝的形式做的 不是引用地址,修改原对象不影响现在的...test,c: 3, };
commonjs 和 es6 模块化的区别
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
- CommonJs 是单个值导出,ES6 Module 可以导出多个
- CommonJs 是动态语法可以写在判断里,ES6 Module 静态语法只能写在顶层
- CommonJs 的 this 是当前模块,ES6 Module 的 this 是 undefined
-
CommonJS(运行时同步加载的,拷贝模块中的对象,浅拷贝)
- 模块可以多次加载,但只会在第一次加载,之后会被缓存,引入的是缓存中的值
- 引入使用:require(“path”)
- 1.如果是第三方模块 只需要填入模块名
- 2.自己定义的模块 需要使用相对路径或者绝对路径
- 导出模块使用:exports.xxx 或 module.exports.xxx 或 module.exports=xxx 或 this.xxx
- !!不管是使用 exports 还是 this ,都需要用点语法的形式导出,因为 他们两个是 module. - exports 的指针 重新赋值将会切断关联
-
Es6 模块(【动态只读引用】,编译时异步加载,有一个独立的模块依赖的解析阶段。ES6 Module 是对模块的引⽤,即 ES6 Module 只存只读,不能改变其值,具体点就是指针指向不能变,类似 const 。)
- 默认导出 export default 变量或者函数或者对象
- 默认引入 import name from “相对或绝对路径”
- 导出的名字和引入的名字可以不一致
- 按需导出 export 需要声明 变量用 const var let 函数用 function
- 按需引入 import {变量名或函数名} form “路径”
- 全部引入 使用 import * as 自定义 name “路径”
- 会将默认导出和按需导出 全部引入
js 宏任务和微任务
在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。
-
同步任务:进入主进程执行
-
异步任务:进入 Event table 注册函数,当指定事情完成时,ET 会将任务移到 Event Queue,主进程任务执行完毕为空,回去 EQ 读取,进入主进程执行,不断重复这个过程,就是 js 的事件循环(Event Loop)
-
宏任务:setTimeout、setInterval、requestAnimationFrame(web)、setImmediate(node)
-
微任务:Promise.then catch finally、MutationObserver(web)、process.nextTick(node)
setTimeout(() => {console.log("内层宏事件4"); //执行后 回调一个宏事件
}, 0);
console.log("外层宏事件1");
new Promise((resolve) => {console.log("外层宏事件2");resolve();
}).then(() => {console.log("微事件1");}).then(() => {console.log("微事件2");});
console.log("外层宏事件3");
// 外层宏事件1 外层宏事件2 外层宏事件3 微事件1 微事件2 内层宏事件4
// 首先浏览器执行js进入第一个宏任务进入主线程, 遇到 setTimeout 分发到宏任务Event Queue中
// 遇到 console.log() 直接执行 输出 外层宏事件1
// 遇到 Promise, new Promise 直接执行 输出 外层宏事件2
// 遇到 console.log() 直接执行 输出 外层宏事件3
// 执行then 被分发到微任务Event Queue中
// 第一轮宏任务执行结束,开始执行微任务 打印 '微事件1' '微事件2'
// 第一轮微任务执行完毕,执行第二轮宏事件,打印setTimeout里面内容'内层宏事件4'console.log("1"); //主线程直接执行
setTimeout(function () {//丢到宏事件队列中console.log("2"); //1process.nextTick(function () {console.log("3"); //3});new Promise(function (resolve) {console.log("4"); //2resolve();}).then(function () {console.log("5"); //4});
});
process.nextTick(function () {console.log("6"); //微事件1
});
new Promise(function (resolve) {console.log("7"); //主线程直接执行resolve();
}).then(function () {console.log("8"); //微事件2
});
//丢到宏事件队列中
setTimeout(function () {console.log("9"); //1process.nextTick(function () {console.log("10"); //3});new Promise(function (resolve) {console.log("11"); //2resolve();}).then(function () {console.log("12"); //4});
});
// 浏览器完整的输出为1,7,6,8,2,4,3,5,9,11,10,12
// 首先浏览器执行js进入第一个宏任务进入主线程, 直接打印console.log('1')
// 遇到 setTimeout 分发到宏任务Event Queue中
// 遇到 process.nextTick 丢到微任务Event Queue中
// 遇到 Promise, new Promise 直接执行 输出 console.log('7');
// 执行then 被分发到微任务Event Queue中
// 第一轮宏任务执行结束,开始执行微任务 打印 6,8
// 第一轮微任务执行完毕,执行第二轮宏事件,执行setTimeout
// 先执行主线程宏任务,在执行微任务,打印'2,4,3,5'
// 在执行第二个setTimeout,同理打印 '9,11,10,12'
// 总结:先执行主进程的:宏任务==》微任务,执行下一队列
异步和单线程
- js 是单线程,只能做一件事
- 浏览器和 nodejs 已经支持 js 启动进程,如 web worker
- JS 和 DOM 渲染公用一个线程,因为 JS 可修改 DOM 结构(一个进行另一个必须停止)
- 异步:(callback 回调函数)不阻塞代码执行,场景:1、网络请求 2、定时器
- 同步:alert()卡住 阻塞代码执行
js 操作 DOM
document.getElementById("div1");
doecument.getElemntsdByTagName("div"); //集合
document.getElementsByClassName("div1"); //集合
document.querySelectorAll("p"); //集合
//兼容所有浏览器获取屏幕宽高
let curWidth =document.documentElement.clientWidth || document.body.clientWidth;
let curHeight =document.documentElement.clientHeight || document.body.clientHeight;
-
节点类型
名称 nodeType nodeName nodeValue(节点值) 元素 1 大写标签名 null 文本 3 #text 文本内容 注释 8 #comment 注释内容 document 9 #document null -
DOM 中的节点关系属性:
- childNodes 获取所有子节点,包含元素,文本,换行,空格, 注释等 类数组类型
- children 获取所有元素子节点(标签元素)低版本浏览器可以拿到注释节点 ie8
- firstChild 获取第一个子节点
- fistElementChild 获取第一个元素子节点
- lastChild 获取所有的子节点中的而最后一个
- lastElementChild
- parentNode 获取父亲节点
- previousSibling 获取哥哥(上一个)节点 (文本,注释,元素)
- previousElementSibling 哥哥的元素节点
- nextSibling 获取弟弟节点 (文本,注释,元素)
- nextElementSibling 弟弟的元素节点
- HTML 中获取不到的最差也是 null,没见过 undefined。
-
property:用 js 属性操作的一种形式,对 js 变量进行修改,修改对象属性,不会体现在 html 结构中
p1.style.width(className)
设置或者获取页面样式 -
attr:设置标签属性,对 dom 节点属性进项修改,修改 html 属性,会体现在 html 中
p1.setAttribute("data-name", "icc"); p1.getetAttribute("data-name"); //icc p1.setAttribute("style", "color:red");
-
property 会比 attr 避免一些重复的 dom 渲染,尽量用 property
// 新建节点:createElement const p1 = document.createElement("p"); p1.innerHtml = "this is p1"; // 插入和移动节点:appendChild div1.appendChild(p1); // 获取父元素:parentNode console.log(p1.parentNode); // 获取子元素列表:childNodes console.log(div1.childNodes); //包括文本元素 // a 你要把谁插入 b 插入谁前面 父元.insertBefore(a,b) insertBefore(a, b); // 参数是要删除的元素 parentNode.removeChild(oA); 父级删除 div1.removeChild(child[0]); // a 谁来替换 new b 替换谁 old 重点就是一动了父元.replaceChild(a,b) replaceChild(a, b); // 克隆节点 true:连内容一起拷贝 cloneNode() / cloneNode(true); // 获取 p 标签 const childP = Array.prototype.slice.call(div.childNodes).filter((child) => {if (child.nodeType === 1) {return true;}return false; });
-
DOM 性能:耗费 cpu
- 1、做一个缓存:把 dom 节点付给一个变量
- 2、将频繁操作的改为一次性操作
// 文档碎片 // 创建文件片段,此时没有插入 DOM 中 const frag=document.createDocumentFragment() for(let i=0,i<10,i++){const li = document.createElement('li')li.innerHTML='this is li'frag.appendChild(li) } // 一次性插入 nodeList.append(frag)
-
BOM
// 如何识别浏览器类型 navigator screen location history const ua = navigator.userAgent; const isChrome = ua.indexOf("Chrome"); console.log(screen.width); //屏幕的宽高 location.href; //网址 location.protocol; //协议 location.host; //域名 location.search; //查询参数 location.hash; location.pathname; history.back(); history.forward();
Ajax (Asynchronous JavaScript And XML)
// ajax: XMLHttpRequest
const xhr = new XMLHttpRequset();
xhr.open("GET", "/data/test.json", true); // true是异步的
xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status === 200) {console.log(xhr.responseTest);}}
};
xhr.send(null);
// post请求:
const postData = {userName: "aa",password: 123,
};
xhr.send(JSON.stringify(postData));
-
xhr.readyState:
- 0 - 未初始化 还没掉用 send()方法
- 1 - 载入中 已调用 send 方法正在发送请求
- 2 - 载入完成 send 方法执行完成,已经接收到全部相应内容
- 3 - 交互 正在解析相应内容
- 4 - 完成 相应内容解析完成,可以在客户端调用
-
同源策略:浏览器的要求,网页和 server 必须同源,协议、域名、端口都一致。
- img 可以用于统计打点,可使用第三方统计服务
- link、script 可以使用 CDN,CDN 一般都是外域
- script 可以实现 JSONP,也需要 server 端配合,服务端可以拼接任何数据返回
-
解决跨域
- jsonp 的原理就是利用
<script>
标签没有同源策略限制,通过<script>
标签 src 属性,发送带有 callback 参数的 GET 请求,服务端将接口返回数据拼凑到 callback 函数中,返回给浏览器,浏览器解析执行,从而前端拿到 callback 函数返回的数据。只能发送 get 一种请求 - 跨域资源共享(CORS)Access-Control-Allow-Origin:*
- 代理 nginx vue 的 proxy
- postMessage
- webSocket
// jsonp 只能发送get一种请求 let script = document.createElement('script'); script.type = 'text/javascript'; // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数 script.src = 'http://localhost:8080/login?user=admin&callback=handleCallback'; document.head.appendChild(script); // 回调执行函数 function handleCallback(res) {console.log(JSON.stringify(res)); } // 服务端返回如下(返回时即执行全局函数): handleCallback({"success": true, "user": "admin"})// jsonp window.callback = function (data) {console.log(data); }; <script src="http://localhost:8080/jsonp.js"></script>; //jsonp.js的内容:执行这个函数吧内容带回去 callback({ name: "abc" });// cors 服务端设置可以跨域 CORS请求设置的响应头字段,都以 Access-Control-开头,Access-Control-Allow-Origin:必选// #proxy服务器 // server { // listen 81; // server_name www.domain1.com;// location / { // proxy_pass http://www.domain2.com:8080; #反向代理 // proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名 // index index.html index.htm;// # 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用 // add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为* // add_header Access-Control-Allow-Credentials true; // } // }let myAjax = function (url, method, type, data) {if (!url) {return Promise.reject(new Error("url 不能为空!"));}if (!method) {method = "GET";}if (!type) {type = "application/json";}if (type === "application/x-www-form-urlencoded" &&typeof data === "object") {let str = "";Object.keys(data).forEach((x) => {str += `${x}=${data[x]}&`;});data = str.replace(/&$/, "");}return new Promise((resolve, reject) => {let xhr = new XMLHttpRequest();xhr.open(method, url);xhr.setRequestHeader("Content-Type", type);xhr.setRequestHeader("access-token", cfg.accessToken);xhr.send(data || null);xhr.onreadystatechange = function () {if (xhr.readyState === this.HEADERS_RECEIVED) {console.log(`Content-Type: ${xhr.getResponseHeader("Content-Type")}`);} else if (xhr.readyState === 4) {if (xhr.status === 200) {return resolve(xhr.response);} else {return reject(xhr.response);}}};}); }; // jquery中使用ajax $.ajax({type:'POST',contentType:'application/json;charset=UTF-8',url:'http://127.0.0.1/admin/list',data:JSON.stringify(list),jsonpCallback: "handleCallback", // 自定义回调函数名success:function(){},error:function(){} }) fetch(url).then()://返回的Promise不会标记为reject,及时返回的404和500,只有网络故障时候回reject,不会从服务端发送和接收任何cookies,必须设置credentials选项 //axios:axios.get().then()
- jsonp 的原理就是利用
存储
- cookie:本身用于浏览器和 server 通讯,借用来做本地存储,可用 document.cookie=”a=100”修改,最大限制 4kb,每次都要发送到服务器,增加请求数据量,
- localStorage:永久存储,H5 专门设计的存储,最大可存 5M,API 简单:setItem getItem,不随 http 请求发送
- sessionStorage:只存在当前会话,浏览器关闭就清空
linux 命令:
- ssh user@192.168.2.97 => 回车输入密码
- ls 查看文件夹
- ls -a 查看所有-all
- ll 车看列表
- clear
- mkdir file
- rm -rf file 删除文件夹
- cd dist
- mv 1.js 2.js 修改文件名
- mv 1.js …/…/product/1.js 移动文件
- cp 1.js 2.js 拷贝
- rm a1.js 删除文件 a1.js
- touch a2.js 创建文件
- vi d.js 编辑文件 i 输入 :wq 写入退出 q!强制退出不保存
- vim 有的话直接打开,没有的话创建打开
- cat package.json 查看
- head package.json 查看头几行
- tail package.json 查看末尾几行
- grep ‘babel’ package.json 查找关键字
JS 中的垃圾
- 1、js 内存管理是自动的
- 2、对象不被引用时就是垃圾
- 3、对象不能从根上访问到是垃圾(不可达)
GC:垃圾回收机制的简写,它可以找到内存中的垃圾并释放和回收空间
-
GC 算法:
-
1、引用计数:设置引用数,判断当前引用数是否为 0
引用计数器 ==> 引用关系改变修改引用数字 ==> 引用数字为 0 立即回收
- 优点:发现垃圾立即回收,最大限度较少程序暂停
- 缺点:无法回收循环引用对象,时间开销大
function fn() {const obj1 = {};const obj2 = {};boj1.name = obj2;obj2.name = obj1; } fn();
-
2、标记清除
分标记和清除两个阶段,遍历所有对象找标记活动对象,遍历所有对象清除没有标记的对象,回收相应空间
- 优点:解决对象循环引用操作
- 缺点:空间碎片化,回收的地址不连续
-
3、标记整理
标记清除的增强,清除阶段先执行整理,移动对象的位置
- 缺点:不会立即回收垃圾对象
- V8 引擎:采用及时编译所以快 内存设限:1.5g/800m
-
分代回收
内存分新生代、老生代,空间复制、标记清除、标记整理、标记增量
- 新生代(From 使用空间,To 空闲空间):存活时间较短的对象,小空间存储(32M/16M)
- 新生代回收采用复制算法 + 标记整理,活动对象在 from 空间,标记整理后将活动对象拷贝到 to 空间,from 与 to 交换空间完成释放。(复制算法:空间换时间),一轮 GC 还存活的新生代需要晋升到老升代空间,to 空间的使用超过 25%也会晋升
- 老生代:主要使用标记清除进行 GC,当新生代晋升空间不足在进行标记整理,标记增量进行效率优化。(标记增量和程序是交替执行的,执行一部分,标记一部分)
-
Performance 工具监控内存
-
监控内存方式:
- 内存泄漏:内存持续升高,没有下降
- 内存膨胀:多数设备上存在性能问题
- 频繁垃圾回收:内存变化图分析
- 浏览器任务管理器:shift+esc
- Timeline 时序图记录:Performance
- 堆快照查找分离 DOM:控制台内存,堆快照
- 判断是否存在频繁的垃圾回收:Timeline 频繁升降,任务管理去数据频繁增加减小
-
-
代码优化:
- 1、慎用全局变量:作用域链顶端,一直存在执行栈到结束,局部作用域出现同名污染全局
- 2、缓存全局变量:获取 dom 存在变量里
- 3、通过原型新增方法
- 4、避开闭包陷阱
- 5、避免属性访问方法的使用
- 6、for 循环的优化,选择最优的循环方法
- 7、文档碎片,克隆优化节点
- 8、直接用字面量替换 new Object 定义
JS 中捕获异常:
- 1、手动捕获 try{ }catch(err){ }finally{ }
- 2、自动捕获:
window.onerror = function (message, source, lineNum, colNum, error) {// 对于跨域的js,如CDN,不会有详细的报错// 对于压缩的js,需要配合sourceMap 反查到未压缩的行和列
};
RAF requestAnimationFrame
想要动画流畅,更新频率要 60 帧/s,即 16.67ms 更新一次视图,setTimeout 要手动控制频率,而 RAF 浏览器会自动控制,后台标签或隐藏 iframe 中,RAF 会暂停,而 setTimeout 依然执行
// 3s把宽度从100px变为640px,即增加540px
// 60帧/s,3s 180帧,每次变化3px
const $div1 = $("#div1");
let curWidth = "100px";
const maxWidth = "640px";
function animate() {curWidth = curWidth + 3;$div1.css("width", curWidth);if (curWidth < maxWidth) {setTimeout(animate, 16.7); //手动控制时间//window.requestAnimationFrame(animate) 浏览器自动控制时间}
}
animate();
浏览器缓存:两个地方用到了缓存,DNS 缓存和页面资源缓存
-
1.DNS 缓存比较简单,就是在浏览器本地把对应的 IP 和域名关联起来
浏览器缓存->系统缓存->本地 host 文件(尽量设置为只读)-> DNS 系统调用请求本地域名服务器 localDNS(LDNS)来解析域名(80%都能找到)->直接请求
-
2.浏览器的资源缓存
-
强缓存
不请求服务器,直接从缓存中读取,chrome=>Network 可以看到该请求返回 200,并且 Size 显示 from disk cache 或 from memory cache。强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control
- Expires:缓存过期时间,指定资源到期的时间,是服务器端的具体的时间点。
Expires=max-age + 请求时间,需要和
Last-modified
结合使用。Expires 是 Web 服务器响应消息头字段,在响应 http 请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。Expires 是 HTTP/1 的产物,受限于本地时间,如果修改本地时间,可能会造成缓存失效。
- Cache-Control:是 HTTP/1.1 的产物。比如设置 Cache-Control:max-age=300,5 分钟内再次加载资源,就会命中强缓存。
cache-control 的更多选项:
no-cache:表示不使用 Cache-Control 的缓存控制方式做前置验证,而是使用 Etag 或者 Last-Modified 字段来控制缓存。设置了 no-cache 之后,并不是说浏览器就不再缓存数据,只是浏览器在使用缓存数据时,需要先确认一下数据是否还跟服务器保持一致。使用的协商缓存
no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- 区别:Expires 是 http1.0 的产物,Cache-Control 是 http1.1 的产物,两者同时存在的话,Cache-Control 优先级高于 Expires。
- 强缓存判断是否缓存的依据来自于是否超出某个时间或者某个时间段,而不关心服务器端文件是否已经更新,这可能会导致加载文件不是服务器端最新的内容,此时我们需要用到协商缓存策略。
- Expires:缓存过期时间,指定资源到期的时间,是服务器端的具体的时间点。
-
协商缓存
就是强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程,主要有以下两种情况:
协商缓存生效,返回 304 和 Not Modified
协商缓存失效,返回 200 和请求结果
协商缓存通过设置两种 HTTP header 实现 Last-Modified 和 ETag
-
Last-Modified(服务端返回)和 If-Modified-Since(请求时候带上)
浏览器在第一次访问资源时,服务器返回资源的同时,在 response header 中添加 Last-Modified 的 header,表示资源在服务器上的最后修改时间,浏览器接收后缓存文件和 header; Last-Modified: Sun, 31 May 2020 05:28:04
浏览器下次请求资源,检测到 Last-Modified 这个 header,添加 If-Modified-Since 这个 header,值就是 Last-Modified 中的值;服务器会根据 If-Modified-Since 中的值与服务器中这个资源的最后修改时间对比,如果没有变化,返回 304 和空的响应体,直接从缓存读取,如果 If-Modified-Since 的时间小于服务器中这个资源的最后修改时间,说明文件有更新,于是返回新的资源文件和 200 状态码
Last-Modified 弊端:
- 1.本地打开缓存文件,即使没有对文件进行修改,也会造成 Last-Modified 被修改,服务端不能命中缓存导致发送相同的资源
- 2.Last-Modified 只能以秒计时,如果在 1s 时间内修改完成文件,那么服务端会认为资源还是命中了,不会返回正确的资源
所以在 HTTP / 1.1 出现了 ETag 和 If-None-Match
-
ETag 和 If-None-Match
流程类似上面。Etag 是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,Etag 就会重新生成。浏览器在下一次加载资源向服务器发送请求时,会将上一次返回的 Etag 值放到 request header 里的 If-None-Match 里,服务器只需要比较客户端传来的 If-None-Match 跟自己服务器上该资源的 ETag 是否一致,就能很好地判断资源相对客户端而言是否被修改过了。如果服务器发现 ETag 匹配不上,那么直接返回 200,将新的资源(当然也包括了新的 ETag)发给客户端;如果 ETag 是一致的,则直接返回 304,客户端直接使用本地缓存即可。
-
两者对比:Last-Modified 是 HTTP/1.0 的产物,而 Etag 是 HTTP/1.1 的产物在精确度上,Etag 要优于 Last-Modified。在性能上,Etag 要逊于 Last-Modified,毕竟 Last-Modified 只需要记录时间,而 Etag 需要服务器通过算法来计算出一个 hash 值。在优先级上,服务器校验优先考虑 Etag
-
-
总结:强制缓存优先于协商缓存,若强制缓存生效则直接使用缓存,若不生效则进行协商缓存,协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,返回 200,重新返回资源和缓存标识,再存入浏览器缓存中;生效则返回 304,继续使用缓存。
-
用户行为对浏览器缓存的影响:
- 1.地址栏输入地址: 查找 disk cache 中是否有匹配。有则使用;没有则发送网络请求。
- 2.普通刷新 (F5):因为 TAB 并没有关闭,因此 memory cache 是可用的,会被优先使用,其次是 disk cache。
- 3.强制刷新 (Ctrl + F5):浏览器不使用缓存,因此发送的请求头部均带有 Cache-control: no-cache(为了兼容,还带了 Pragma: no-cache),服务器直接返回 200 和最新内容。
-
babel 编译原理
- babylon 将 ES6/ES7 代码解析成 AST
- babel-traverse 对 AST 进行遍历转译,得到新的 AST
- 新 AST 通过 babel-generator 转换成 ES5
函数柯里化
在一个函数中,首先填充几个参数,然后再返回一个新的函数的技术,称为函数的柯里化。通常可用于在不侵入函数的前提下,为函数 预置通用参数,供多次重复调用。
const add = function add(x) {return function (y) {return x + y;};
};
const add1 = add(1);
add1(2) === 3;
add1(20) === 21;
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 时间管理专家的 Linux 工具
无论你是需要帮助来保持专注、保持及时性,还是为了找到避免重复的捷径,这些 Linux 工具能够帮助你。生产力是一个主观术语,但从本质上讲,它是衡量特定任务完成效率的标准。每个人都有不同的方式来提高他们的生产力:有些…...
2024/5/2 21:52:16 - 云服务器Linux系统安装Redis
1. 下载安装包 百度云链接:https://pan.baidu.com/s/1XLoTewKdkAiGd8gowQvKlw 提取码:wtyi 里面有Tomcat,JDK8,Nginx,Redis的安装包 2. 将安装包放入服务器 使用Xftp将文件放置在服务器的home文件夹下。 3. 安装…...
2024/5/2 21:52:11 - jQuery的概念
事件的加载 三种方式 //加载事件页面加载完毕立即执行 $(document).ready(function(){alert("jdksj"); }) $(function(){alert("jdksj"); }) jQuery(document).ready(function(){alert("djksjfk"); })操作结点 原生方法 window.onloadfuncti…...
2024/5/2 21:52:07 - node设置响应头,pdf类型响应头
Ps:我太年轻,照着网上抄了,就导致报错了 一般不设置是没问题,走默认类型,但像如我用了a标签来下载文件,需比较依赖响应头了,a标签有的download属性有兼容问题 所有文件类型的请求头字符串&am…...
2024/5/2 21:52:04 - [PTA]题目集导航
PTA(程序设计类实验辅助教学平台)题目集导航基础编程题目集浙大版《C语言程序设计(第3版)》题目集浙大版《C语言程序设计实验与习题指导(第3版)》题目集中国大学MOOC - 陈越、何钦铭 - 数据结构 - 起步能力…...
2024/5/7 13:17:29 - 如何对你的 Linux 系统进行压力测试
如果你想了解 Linux 服务器在重压之下的运行情况,那么给 Linux 服务器施加压力是个不错的主意。在这篇文章中,我们将看一些工具,可以帮助你增加服务器压力并衡量结果。为什么你会想给你的 Linux 系统施加压力呢?因为有时你可能想知…...
2024/5/2 21:51:55 - java开发安装软件及教程
oracle官网: http://www.oracle.com jdk: https://www.oracle.com/technetwork/java/javase/downloads/index.html /usr/libexec/java_home -V 查找jdk安装路径 创建 .bash_profile 文件,并配置 JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Conte…...
2024/5/2 19:31:56 - 跳出接力break、goto
如果有多层循环,break只能跳出最近的那层循环。 只在每层写break的话,不行。需要在最内层break的情况下,才执行外一层的break, 即定义标记变量在最内层break前加个标记变量。外一层加if(标记变量1)break;…...
2024/5/2 21:51:51 - LocalSolver快速入门指南(连载三十一) -- 外部函数实例 C++
外部函数C代码实例 在C中,必须扩展LSExternalFunction类,特别是call()方法来实现外部函数(第1步)。 然后(第2步),实例化函数并使用createExternalFunction()方法将其转换为一个LSExpression。 最后(步骤3),可以在O_Call表达式中…...
2024/5/2 21:51:48 - C++ this指针调整
#include "stdafx.h" #include <iostream> #include <vector> #include <algorithm> #include <map> using namespace std;class A { public:char a;A(){printf("A::A()的this地址: %p\n", this);}void funA(){printf("A::fu…...
2024/5/2 21:51:43 - 从滴滴的Flink CEP引擎说起
CEP业务场景 复杂事件处理(Complex Event Process,简称CEP)用来检测无尽数据流中的复杂模 式,拥有从不同的数据行中辨识查找模式的能力。模式匹配是复杂事件处理的一个强 大援助。 例子包括受一系列事件驱动的各种业务流程&#x…...
2024/5/2 21:51:39 - GH1131/gh131高温合金耐磨耐腐蚀性能
GH1131是一种以钨、钼、铌、氮等元素复合固溶强化的高性能铁基高温合金,含镍量约为28%,但其热强性水平却与GH3044合金。 GH1131(GH131)概述 GH1131是一种以钨、钼、铌、氮等元素复合固溶强化的高性能铁基高温合金,含镍量约为28%,…...
2024/5/2 21:51:36 - IList<IList<int>>这个类型怎么实例化?
IList<IList<int>> _resnew List<IList<int>>(); _res.Add(new List<int>{1}); 相关应用:LeetCode46 全排列 参考资料:https://tieba.baidu.com/p/6102477516?red_tag2294823006...
2024/5/2 21:51:32 - Java 第一个程序(命令行运行)
Java 第一个程序(命令行运行) 首先我们默认已经安装好JDK并且配置好环境(没有安装好的可以查看上一篇博客点击跳转) 可以使用记事本来写我们的第一个Java程序 找一个路径下,创建一个文本文件 创建完成后,…...
2024/5/2 21:51:27 - 如何解决神经网络训练时loss不下降的问题
参考:https://blog.ailemon.net/2019/02/26/solution-to-loss-doesnt-drop-in-nn-train/...
2024/5/2 21:51:24 - 跟我上医院蹭WIFI,利用这三个Python脚本无限恶搞朋友电脑
Python 无限恶搞朋友电脑,别提有多爽了,哈哈,打造自己的壁纸修改器,电脑无限锁屏, 无线弹窗,都在这里!!! 修改电脑桌面壁纸 工具使用 开发环境:python3.7&…...
2024/5/2 21:51:20 - 【预测模型】基于粒子群算法优化BP神经网络预测风电功率matlab源码
1 模型 针对于BP神经网络预测模型,收敛速度慢,精度较低,容易陷入局部极小值等缺点,提出了一种粒子群优化BP神经网络预测模型的算法.在该算法中,粒子群优化BP神经网络预测模型的初始权值和阈值,然后训练BP神经网络预测模型并预测.将该算法应用到几个典型的混沌时间序列预测.实验…...
2024/5/2 21:51:15 - STM32F103Cx用芯片tlc5615做DAC转换
1、打开原理图,查看芯片对应的相应管脚 2、打开STM32CubeMX,添加相应管脚配置 3、输入的配置为无上下拉,输出该芯片对应的引脚配置和上图相同,一键生成代码,打开代码 4、新建“BspVout.c”和“BspVout.h”文件并添加在…...
2024/5/6 23:11:30 - virtualbox 增强工具安装 vmware tools
1. 在开启运行的虚拟机界面 菜单栏Devices => Insert Guest Additions CD images2. 运行光驱中的安装程序虚拟机系统是Linux 自动挂载到/media下windows情况下挂载到光驱盘 打开运行安装3. 安装好了reboot4. 调节界面缩放比例Auto-resize guest display...
2024/5/2 21:51:07 - 876.链表的中间结点
class Solution { public:ListNode* middleNode(ListNode* head) {ListNode* slowhead;ListNode* fasthead;while(fast->next){slowslow->next;if(fast->next->next){fastfast->next->next;}else{fastfast->next;} } return slow;} }; 哼哼,链…...
2024/5/2 21:51:04
最新文章
- vcenter7安装nsx
登录控制台 Get services...
2024/5/8 17:38:45 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/5/7 10:36:02 - 《c++》多态案例一.电脑组装
一.代码展示 #include <iostream> using namespace std; class CPU { public://抽象计算函数virtual void calculate() 0;};class CVideoCard { public://抽象显示函数virtual void display() 0;}; class Memory { public://抽象存储函数virtual void storage() 0;};…...
2024/5/5 8:48:19 - [实战经验]Mybatis的mapper.xml参数#{para}与#{para, jdbcType=BIGINT}有什么区别?
在MyBatis框架中,传入参数使用#{para}和#{para, jdbcTypeBIGINT}的有什么区别呢? #{para}:这种写法表示使用MyBatis自动推断参数类型,并根据参数的Java类型自动匹配数据库对应的类型。例如,如果参数para的Java类型是Lo…...
2024/5/8 6:05:45 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/8 6:01:22 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/7 9:45:25 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/5/4 23:54:56 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/7 14:25:14 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/5/4 23:54:56 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/5/4 23:55:05 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/5/4 23:54:56 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/5/7 11:36:39 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/5/4 23:54:56 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/6 1:40:42 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/5/4 23:54:56 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/5/4 23:55:17 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/5/7 9:26:26 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/5/4 23:54:56 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/4 23:55:06 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/5 8:13:33 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/5/4 23:55:16 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/5/4 23:54:58 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/6 21:42:42 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/5/4 23:54:56 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57