学习js遇到的疑问和js基础都记录在这里,持续更新中。javascript
/b+/g 至少出现一次b(1~n次)php
/b*/g 能够不出现b,也能够出现一次或屡次(0~n次)css
/b{n,m}/g 最少出现n次b,最多出现m次b(n~m次)html
/colou?r/g 能够匹配color或colour,?表示前面的字符最多只出现一次(0次或1次)前端
1.全局变量不会被回收java
2.局部变量会被回收,也就是函数一旦运行完之后,函数内部的东西都会被销毁node
3.只要被另一个做用域所引用就不会被回收jquery
基本数据类型:undefined、null、string、number、boolean、symbolios
复杂数据类型:objectes6
引用类型:array、function、object
typeof
对一个值使用typeof操做符可能返回:
undefined、string、number、boolean、symbol、object(对象或null)、function
console.log(typeof 2); // number console.log(typeof true); // boolean console.log(typeof 'str'); // string console.log(typeof []); // object []数组的数据类型在 typeof 中被解释为object console.log(typeof function(){}); // function console.log(typeof {}); // object console.log(typeof undefined); // undefined console.log(typeof null); // object null 的数据类型被 typeof 解释为 object
instanceof
只有引用数据类型(Array,Function,Object)被精准判断,其余(数值Number,布尔值Boolean,字符串String)字面值不能被instanceof精准判断。
console.log(2 instanceof Number); // false console.log(true instanceof Boolean); // false console.log('str' instanceof String); // false console.log([] instanceof Array); // true console.log(function(){} instanceof Function); // true console.log({} instanceof Object); // true // console.log(undefined instanceof Undefined); // console.log(null instanceof Null);
constructor
console.log((2).constructor === Number); // true console.log((true).constructor === Boolean); // true console.log(('str').constructor === String); // true console.log(([]).constructor === Array); // true console.log((function() {}).constructor === Function); // true console.log(({}).constructor === Object); // true
用costructor来判断类型看起来是完美的,然而,若是我建立一个对象,更改它的原型,这种方式也变得不可靠了。
function Fn(){}; Fn.prototype = new Array(); var f = new Fn(); console.log(f.constructor === Fn); // false console.log(f.constructor === Array); // true
object.prototype.toString.call()
console.log(Object.prototype.toString.call(2)); // [object Number] console.log(Object.prototype.toString.call(true)); // [object Boolean] console.log(Object.prototype.toString.call('str')); // [object String] console.log(Object.prototype.toString.call([])); // [object Array] console.log(Object.prototype.toString.call(function(){})); // [object Function] console.log(Object.prototype.toString.call({})); // [object Object] console.log(Object.prototype.toString.call(undefined)); // [object Undefined] console.log(Object.prototype.toString.call(null)); // [object Null]
使用 Object 对象的原型方法 toString ,使用 call 进行狸猫换太子,借用Object的 toString 方法结果精准的显示咱们须要的数据类型。就算咱们改变对象的原型,依然会显示正确的数据类型。
详细请看这篇文章:https://www.cnblogs.com/humin...
with、try...catch、eval
Ajax技术核心就是XMLHttpRequest对象。
(1)设置请求参数(请求方式,请求页面的相对路径,是否异步)
(2)设置回调函数,一个处理服务器响应的函数,使用 onreadystatechange ,相似函数指针
(3)获取异步对象的readyState 属性:该属性存有服务器响应的状态信息。每当 readyState 改变时,onreadystatechange 函数就会被执行。
(4)判断响应报文的状态,若为200说明服务器正常运行并返回响应数据。
(5)读取响应数据,能够经过 responseText 属性来取回由服务器返回的数据。
var xhr = new XMLHttpRequest(); // 建立Ajax对象 xhr.open('get', 'aabb.php', true); // xhr发送请求 xhr.send(null); xhr.onreadystatechange = function() { // xhr获取响应 if(xhr.readyState == 4) { if(xhr.status == 200) { console.log(xhr.responseText); } } } /* ajax返回的状态: 0:(未初始化)请求尚未创建(open执行前) 1:(载入)请求创建了还没发送(执行了open) 2:(载入完成)请求正式发送,send()方法执行完成,已经接收到所有响应内容(执行了send) 3:(交互)请求已受理,有部分数据能够用,但尚未处理完成,正在解析响应内容 4:(完成)响应内容解析完成,能够在客户端调用了 */
Ajax:
ajax,最先出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间若是有前后关系的话,就会出现回调地狱。
Jquery Ajax:
是jQuery框架中的发送后端请求技术,因为jQuery是基于原始的基础上作的封装,因此,jquery Ajax天然也是对原始ajax的封装
$.ajax({ type: 'POST', url: url, data: data, dataType: dataType, success: function () {}, error: function () {} });
优缺点:
Fetch:
fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。
可是,必定记住fetch不是ajax的进一步封装,而是原生js。Fetch函数就是原生js,没有使用XMLHttpRequest对象。
try { let response = await fetch(url); let data = response.json(); console.log(data); } catch(e) { console.log("Oops, error", e); }
axios:
axios不是原生JS的,须要进行安装,它不但能够在客户端使用,并且能够在nodejs端使用。Axios也能够在请求和响应阶段进行拦截。一样也是基于promise对象的。
https://blog.csdn.net/Roselan...
axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
优缺点:
"/ /"这个是固定写法,"s"是转移符号用以匹配任何空白字符,包括空格、制表符、换页符等等,"g"表示全局匹配将替换全部匹配的子串,若是不加"g"当匹配到第一个后就结束了。
这个例子的意思就是将原字符串中的全部空白字符替换成"",好比"abc d efg "字样的字符串使用这个函数后将变成"abcdefg"
通常用来把字符串中全部的空格去掉
forEach()
: 数组中的每一个元素执行一次回调函数map()
: 返回一个由原数组中的每一个元素调用一个指定方法后的返回值组成的新数组示例
下方提供了一个数组,若是咱们想将其中的每个元素翻倍,咱们可使用map
和forEach
来达到目的。
let arr = [1, 2, 3, 4, 5];
ForEach
注意,forEach
是不会返回有意义的值的。
咱们在回调函数中直接修改arr
的值。
arr.forEach((num, index) => { return arr[index] = num * 2; });
Map
let doubled = arr.map(num => { return num * 2; });
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置,若是没有找到返回-1
search方法用于检索字符串中指定的子字符串,检索与正则表达式相匹配的子字符串。若是没有找到,返回-1。
indexOf与search的区别
search()的参数必须是正则表达式,而indexOf()的参数只是普通的字符串。indexOf()是比search()更加底层的方法。
若是只是对一个具体字符串来检索,那么使用indexOf()的系统资源消耗更小,效率更高;若是查找具备某些特征的字符串(例如查找以a开头,后面是数字的字符串),那么indexOf()就无能为力,必需要使用正则表达式和search()方法了。
大可能是时候用indexOf()不是为了真的想知道子字符串的位置,而是想知道长字符串中有没有包含这个子字符串。r若是返回索引为-1,那么说明没有,反之则有。
slice() 方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。
stringObject.slice(start,end)
substring() 方法用于提取字符串中介于两个指定下标之间的字符。
stringObject.substring(start,stop)
substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符。
stringObject.substr(start,length)
String 对象的方法 slice()、substring() 和 substr() (不建议使用)均可返回字符串的指定部分。slice() 比 substring() 要灵活一些,由于它容许使用负数做为参数。slice() 与 substr() 有所不一样,由于它用两个字符的位置来指定子串,而 substr() 则用字符位置和长度来指定子串。
还要注意的是,String.slice() 与 Array.slice() 类似。
slice() 方法可从已有的数组中返回选定的元素。
arrayObject.slice(start,end)
splice() 方法主要用途是向数组的中部插入项。
arrayObject.splice(index,howmany,item1,.....,itemX)
index | 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。 |
---|---|
howmany | 必需。要删除的项目数量。若是设置为 0,则不会删除项目。 |
item1, ..., itemX | 可选。向数组添加的新项目。 |
语法:Obejct.assign(target,...sources)
用途:未来自一个或多个源对象中的值复制到一个目标对象,它将返回目标对象。其中对象的继承属性和不可枚举属性是不能拷贝的,因此不能使用它来实现深拷贝。
第一级属性深拷贝,从第二级属性开始就是浅拷贝。
若是多个源对象具备同名属性,则排位靠后的源对象会覆盖排位靠前的。但null或undefined被视为空对象同样对待,不会覆盖。
var receiver = {}; Object.assign(receiver, { type: "js", name:"file.js" }, { type: "css" } ) console.log(receiver); // {type: "css", name: "file.js"}
//实现 deepAssign({a: {b: 1, c: 2}}, {a: {c: 3}}); //=> {a: {b: 1, c: 3}} // 只有两个对象 function deepAssign(obj1, obj2){ for(var item in obj2){ obj1[item] = typeof obj2[item] === 'object' ? deepClone(obj1[item], obj2[item]) : obj2[item]; } return obj1; } // 通用 function deepAssign() { var args = Array.from(arguments); return args.reduce(deepClone, args[0]); function deepClone(target, obj){ if(!target) target = Array.isArray(obj) ? [] : {}; for(key in obj){ target[key] = typeof obj[key] ==="object" ? deepClone(target[key], obj[key]) : obj[key] } return target; } }
一、类数组对象:所谓类数组对象,最基本的要求就是具备length属性的对象。
二、Array.from()方法就是将一个类数组对象或者可遍历对象转换成一个真正的数组。
Array.from有三个参数,Array.from(arrayLike[, mapFn[, thisArg]]),
arrayLike:想要转换成数组的伪数组对象或可迭代对象;
mapFn:若是指定了该参数,新数组中的每一个元素会执行该回调函数;
thisArg:可选参数,执行回调函数 mapFn 时 this 对象。
该方法的返回值是一个新的数组实例(真正的数组)。
例1:Array.from ({length:n}, Fn) 将类数组转换为数组
Array.from({length:3}, () => 'jack') //["jack", "jack", "jack"] Array.from({length:3}, item => (item = {'name':'shao','age':18})) //[{'name':'shao','age':18}, {'name':'shao','age':18}, {'name':'shao','age':18}] Array.from({length:2}, (v, i) => item = {index:i}); //生成一个index从0到4的数组对象[{index: 0},{index: 1}]
let array = { 0: 'name', 1: 'age', 2: 'sex', 3: ['user1','user2','user3'], 'length': 4 } let arr = Array.from(array) console.log(arr) // ['name','age','sex',['user1','user2','user3']]
若是将上面代码中length属性去掉arr将会是一个长度为0的空数组,若是将代码修改一下,就是具备length属性,可是对象的属性名再也不是数字类型的,而是其余字符串型的,代码以下:
let array = { 'name': 'name', 'age': 'age', 'sex': 'sex', 'user': ['user1','user2','user3'], 'length': 4 } let arr = Array.from(array ) console.log(arr) // [ undefined, undefined, undefined, undefined ]
会发现结果是长度为4,元素均为undefined的数组,因而可知,要将一个类数组对象转换为一个真正的数组,必须具有如下条件:
(1)该类数组对象必须具备length属性,用于指定数组的长度。若是没有length属性,那么转换后的数组是一个空数组。
(2)该类数组对象的属性名必须为数值型或字符串型的数字
该类数组对象的属性名能够加引号,也能够不加引号
例2:Array.from (obj, mapFn)
obj指的是数组对象、相似数组对象或者是set对象,map指的是对数组中的元素进行处理的方法。
let arr = [1,1,2,5,5,6,7,8,9] let set = new Set(arr) console.log(Array.from(set)) // [1, 2, 5, 6, 7, 8, 9]
//将数组中布尔值为false的成员指为0 Array.from([1, ,2,3,3], x => x || 0) //[1,0,2,3,3] //将一个相似数组的对象转为一个数组,并在原来的基础上乘以2倍 let arrayLike = { '0': '2', '1': '4', '2': '5', length: 3 } Array.from(arrayLike, x => x*2) //[4,8,10] //将一个set对象转为数组,并在原来的基础上乘以2倍 Array.from(new Set([1,2,3,4]), x => x*2) //[2,4,6,8]
例3:Array.from(string) 将字符串转换为数组
Array.from('abc') //['a','b','c']
例子4——将Map解构转为数组,最方便的作法就是使用扩展运算符(...)
const myMap = new Map().set(true, 7) console.log(myMap); //Map(1) {true => 7} console.log([...myMap]); //[true ,7]
一、利用ES6 Set去重(ES6中最经常使用)
function unique (arr) { return Array.from(new Set(arr)) } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)) //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
不考虑兼容性,这种去重的方法代码最少。这种方法没法去掉“{}”空对象。
二、利用for嵌套for,而后splice去重(ES5中最经常使用)
function unique(arr){ for(var i=0; i<arr.length; i++){ for(var j=i+1; j<arr.length; j++){ if(arr[i]==arr[j]){ arr.splice(j,1); j--; } } } return arr; } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)) //[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}没有去重,两个null直接消失了
三、for...of + includes()
双重for循环的升级版,外层用 for...of 语句替换 for 循环,把内层循环改成 includes()
先建立一个空数组,当 includes() 返回 false 的时候,就将该元素 push 到空数组中
相似的,还能够用 indexOf() 来替代 includes()
function unique(arr) { var result = [] for (var i of arr) { !result.includes(i) && result.push(i) } return result } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)) // [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}] //NaN、{}没有去重
四、利用indexOf去重
function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!'); return; } var array = []; for (var i = 0; i < arr.length; i++) { if (array.indexOf(arr[i]) === -1) { array.push(arr[i]); } } return array; } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)) // [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…}, {…}] //NaN、{}没有去重
五、利用sort()
function unique(arr) { if (!Array.isArray(arr)) { console.log('type error!') return; } arr = arr.sort() var arrry= [arr[0]]; for (var i = 1; i < arr.length; i++) { if (arr[i] !== arr[i-1]) { arrry.push(arr[i]); } } return arrry; } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)) // [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined] // NaN、{}没有去重
6 、利用hasOwnProperty
function unique(arr) { var obj = {}; return arr.filter(function(item, index, arr){ return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true) }) } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)) //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}] //全部的都去重了
七、利用filter
function unique(arr) { return arr.filter(function(item, index, arr) { //当前元素,在原始数组中的第一个索引==当前索引值,不然返回当前元素 return arr.indexOf(item, 0) === index; }); } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)) //[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]
八、利用Map数据结构去重
function arrayNonRepeatfy(arr) { let map = new Map(); let array = new Array(); // 数组用于返回结果 for (let i = 0; i < arr.length; i++) { if(map.has(arr[i])) { // 若是有该key值 map.set(arr[i], true); } else { map.set(arr[i], false); // 若是没有该key值 array.push(arr[i]); } } return array; } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(arrayNonRepeatfy(arr)) //[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined] // {}没去
建立一个空Map数据结构,遍历须要去重的数组,把数组的每个元素做为key存到Map中。因为Map中不会出现相同的key值,因此最终获得的就是去重后的结果。
九、利用reduce+includes
function unique(arr){ return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]); } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)); // [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]
十、for...of + Object
首先建立一个空对象,而后用 for 循环遍历
利用对象的属性不会重复这一特性,校验数组元素是否重复
function unique(arr){ let result = [] let obj = {} for (let i of arr) { if (!obj[i]) { result.push(i) obj[i] = 1 } } return result } var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}]; console.log(unique(arr)); // [1, "true", 15, false, undefined, null, NaN, 0, "a", {…}]
const objArr = [{ name: '名称1' },{ name: '名称2' },{ name: '名称3' },{ name: '名称1' },{ name: '名称2' }] const obj = {} const newObjArr = [] for(let i = 0; i < objArr.length; i++){ if(!obj[objArr[i].name]){ newObjArr.push(objArr[i]); obj[objArr[i].name] = true } } console.log(newObjArr); /*结果: [{ name: '名称1' },{ name: '名称2' },{ name: '名称3' }] */
const objArr = [{ name: '名称1' },{ name: '名称2' },{ name: '名称3' },{ name: '名称1' },{ name: '名称2' }] const obj = {} const newObjArr = objArr.reduce((prev, curr)=>{ obj[curr.name] ? true : obj[curr.name] = true && prev.push(curr); return prev }, []) console.log(newObjArr)
由于你用的fetch post修改了请求头,致使fetch第一次发送一个options请求,询问服务器是否支持修改的请求头,如过服务器支持,那么将会再次发送真正的请求。
什么是跨域
JSONP:ajax请求受同源策略影响,不容许进行跨域请求,而script标签src属性中的连接却能够访问跨域的js脚本,利用这个特性,服务端再也不返回JSON格式的数据,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
JSONP的缺点:
JSON只支持get,由于script标签只能使用get请求;
JSONP须要后端配合返回指定格式的数据。
ajax与jsonp的区别
如何实现跨域
JSONP:经过动态建立script,再请求一个带参网址实现跨域通讯。
document.domain + iframe跨域:两个页面都经过js强制设置document.domain为基础主域,就实现了同域。
location.hash + iframe跨域:a欲与b跨域相互通讯,经过中间页c来实现。 三个页面,不一样域之间利用iframe的location.hash传值,相同域之间直接js访问来通讯。
window.name + iframe跨域:经过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。
postMessage跨域:能够跨域操做的window属性之一。
CORS:服务端设置Access-Control-Allow-Origin便可,前端无须设置,若要带cookie请求,先后端都须要设置。
代理跨域:起一个代理服务器,实现数据的转发
app.bundle
的大小,让浏览器并行下载资源文件,提升下载速度;app.bundle
的体积,在调用某个组件时再加载对应的js文件;js原生获取的dom是一个对象,jQuery对象就是一个数组对象,其实就是选择出来的元素的数组集合,因此说他们二者是不一样的对象类型不等价。
原生DOM对象转jQuery对象:
var box = document.getElementById('box'); var $box = $(box);
jQuery对象转原生DOM对象:
var $box = $('#box'); var box = $box[0];
区别
1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用
2.深拷贝: 建立一个新的对象和数组,将原对象的各项属性的“值”(数组的全部元素)拷贝过来,是“值”而不是“引用”
为何要使用深拷贝?
咱们但愿在改变新的数组(对象)的时候,不改变原数组(对象)
深拷贝数组
1.直接遍历
function copyArr(arr) { let res = [] for (let i = 0; i < arr.length; i++) { res.push(arr[i]) } return res } var arr = [1,2,3,4,5] var arr2 = copyArr(arr)
2.slice()
var arr = [1,2,3,4,5] var arr2 = arr.slice()
3.concat()
var arr = [1,2,3,4,5] var arr2 = arr.concat()
深拷贝对象
1.迭代递归法
这是最常规的方法,思想很简单:就是对对象进行迭代操做,对它的每一个值进行递归深拷贝。
function deepClone(obj){ var newObj= obj instanceof Array ? []:{}; for(var item in obj){ var temple= typeof obj[item] == 'object' ? deepClone(obj[item]):obj[item]; newObj[item] = temple; } return newObj; }
2.ES6的Object.assign(除了根属性是深拷贝,其他都是浅拷贝)
3.ES6扩展运算符:...
“一招鲜,吃遍天” ——序列化反序列化法
JSON.parse(JSON.stringify(XXXX))
var array = [ { number: 1 }, { number: 2 }, { number: 3 } ]; var copyArray = JSON.parse(JSON.stringify(array)) copyArray[0].number = 100; console.log(array); // [{number: 1}, { number: 2 }, { number: 3 }] console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]
它也只能深拷贝对象和数组,对于其余种类的对象,会失真。这种方法比较适合日常开发中使用,由于一般不须要考虑对象和数组以外的类型。
方式1:splice函数
arrayObject.splice(index,howmany,element1,.....,elementX)
index:必选,规定从何处添加/删除元素。
howmany:必选,规定应该删除多少元素。未规定此参数,则删除从 index 开始到原数组结尾的全部元素。
element1:可选,规定要添加到数组的新元素。
<script type ="text/javascript"> var arr = [1,2,3,4]; arr.splice(0,arr.length); </script>
方式2:给数组的length赋值为0
<script type ="text/javascript"> var arr = [1,2,3,4]; arr.length = 0; </script>
赋予数组的长度小于自己的长度,数组中后面的元素将被截断。
赋予数组的长度大于自己的长度,将扩展数组长度,多的元素为undefined。
方式3:直接赋予新数组 []
<script type ="text/javascript"> var arr = [1,2,3,4]; arr = []; </script>
这种方式为将arr从新复制为空数组,以前的数组若是没有被引用,将等待垃圾回收。
待所有完成以后统一执行
let p1 = new Promise((resolve, reject) => { resolve('成功了') }) let p2 = new Promise((resolve, reject) => { resolve('success') }) let p3 = Promise.reject('失败') Promise.all([p1, p2]).then((result) => { console.log(result) //['成功了', 'success'] }).catch((error) => { console.log(error) }) Promise.all([p1,p2,p3]).then((result) => { console.log(result) }).catch((error) => { console.log(error) // 失败了,打出 '失败' })
let wake = (time) => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(`${time / 1000}秒后醒来`) }, time) }) } let p1 = wake(3000) let p2 = wake(2000) Promise.all([p1, p2]).then((result) => { console.log(result) // [ '3秒后醒来', '2秒后醒来' ] }).catch((error) => { console.log(error) })
须要特别注意的是,Promise.all得到的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即使p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程当中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问能够解决这个问题。
function promiseAll(promises) { return new Promise((resolve, reject) => { let resultCount = 0; let results = new Array(promises.length); for (let i = 0; i < promises.length; i++) { promises[i].then(value => { resultCount++; results[i] = value; if (resultCount === promises.length) { return resolve(results) } }, error => { reject(error) }) } }) } let p1 = new Promise(resolve => resolve('p1')) let p2 = new Promise(resolve => resolve('p2')) let p3 = Promise.reject('p3 error') promiseAll([p1, p2]).then(results => { console.log(results) // ['p1', 'p2'] }).catch(error => { console.log(error) }) promiseAll([p1, p2, p3]).then(results => { console.log(results) }).catch(error => { console.log(error) // 'p3 error' })
只要有一个完成就执行,返回为最早完成的
let p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') },1000) }) let p2 = new Promise((resolve, reject) => { setTimeout(() => { reject('failed') }, 500) }) Promise.race([p1, p2]).then((result) => { console.log(result) }).catch((error) => { console.log(error) // 打开的是 'failed' })
var a = 100 function F1() { var b = 200 function F2() { var c = 300 console.log(a) // a是自由变量,向父级做用域寻找a,未果,再向上一级父级做用域寻找a console.log(a) // b是自由变量,向父级做用域寻找b console.log(a) } F2() } F1() // 自由变量不断地往父级做用域去找,造成一个链式结构
1.核心(ECMAScript) ——提供核心语言功能
2.文档对象模型(Dom) ——提供访问和操做网页内容的方法和接口
3.浏览器对象模型(Bom) ——提供与浏览器交互的方法和接口
defer=“defer”
defer属性:代表脚本在执行时不会影响页面的构造,也就是说,脚本会被延迟到整个页面都解析完毕再运行
var result = “a” < 3; // false,由于“a”被转化成了NaN
根据规则,任何操做数与NaN进行关系比较,结果都是false
function doadd() { if (arguments.length == 1) { alert(arguments[0] + 10); } else if (arguments.length == 2) { alert(arguments[0] + arguments[1]); } } doAdd(10) // 20 doAdd(30, 20) // 50
一、递归
function flatArr(arr) { var newArr = []; arr.forEach((val) => { if (Array.isArray(val)) { newArr = newArr.concat(flatArr(val)) } else { newArr.push(val) } }) return newArr; }
二、reduce
function flatArr(arr) { return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flatArr(cur) : cur), []) }
3.利用数组join()或toString()方法
// join() function flatArr(arr) { arr.join().split(',') return JSON.parse(`[${arr.join()}]`) } // toString() function flatArr(arr) { arr.toString().split(',') return JSON.parse(`[${arr.toString()}]`) }
4.es6数组的flat()方法 (浏览器版本太低不支持)
flat方法默认打平一层嵌套,也能够接受一个参数表示打平的层数,传 Infinity 能够打平任意层。
function flatArr(arr) { return arr.flat(Infinity); }
const sleep = (timeountMS) => new Promise((resolve) => { setTimeout(resolve, timeountMS); }); (async () => { console.log('11111111, ' + new Date()); await sleep(2000); console.log('22222222, ' + new Date()); await sleep(2000); console.log('33333333, ' + new Date()); })();
1.设置cookie一天后过时
function setCookie(name,expireday){ var dayobject = new Date(); // Date()函数获取当前的日期和时间 // getTime()函数获取的事1970年1月1号至今的毫秒数 // 注意要多加8小时,咱们位于东八区比标准时间相差8小时 var daynum = dayobject.getTime() + expireday*(24+8)*60*60*1000; // 计算过时时间毫秒数 dayobject.setTime(daynum); // 设置超时的时间 alert('name=' + name + ';' + 'expires=' + dayobject.toGMTString()); document.cookie = 'name=' + name + ';' + 'expires=' + dayobject.toGMTString(); } setCookie('coco',1)
2.设置cookie立刻过时
function delCookie(name){ var expires = new Date(); expires.setTime(expires.getTime() - 1); document.cookie = 'name='+name+';'+'expires=' + expires.toGMTString(); } // 设置cookie的过时时间是比当前时间提早一秒,也就是立马过时了。