记录 js 常用方法
js 类型判断
- Object.prototype.toString
// 以下是11种:
var number = 1; // [object Number]
var string = "123"; // [object String]
var boolean = true; // [object Boolean]
var und = undefined; // [object Undefined]
var nul = null; // [object Null]
var obj = { a: 1 }; // [object Object]
var array = [1, 2, 3]; // [object Array]
var date = new Date(); // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g; // [object RegExp]
var func = function a() {}; // [object Function]
function checkType() {
for (var i = 0; i < arguments.length; i++) {
console.log(Object.prototype.toString.call(arguments[i]));
}
}
checkType(
number,
string,
boolean,
und,
nul,
obj,
array,
date,
error,
reg,
func
);
Object 对象
- Object.defineProperty(obj,prop,descriptor)
vue2.0 数据劫持就是使用此方法 - hasOwnProperty()
判断对象自身属性中是否具有指定的属性。
obj.hasOwnProperty(‘name’) - Object.is()
判断两个值是否相对返回布尔值
- Object.keys()、Object.values()
方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for…in 循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )
- Object.freeze()
冻结一个对象,阻止修改现有属性特性的值,并阻止添加新属性
- Object.assign(target,source1,source2,…)
对象合并
数组
- slice() 截取数组,不改变原数组
- splice() 更新数组,改变原数组
- forEach()、map()、filter()、some()、every() 迭代方法,不改变原数组
- every
arr.every((currentValue , index , arr) => {}, thisValue) 判断数组中的每一项是否都满足条件,全部符合就会返回 true,否则 false。
const arr = [1, 2, 3];
const str = arr.every((currentValue) => {
return currentValue > 1;
});
console.log(str); // false
- some
判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回 true,不再往下执行
arr.some((currentValue, index, arr) => {}, thisValue);
const arr = [1, 2, 3];
const str = arr.some((currentValue) => {
console.log(currentValue);
return currentValue > 1;
});
// 1
// 2
console.log(str); // true
- keys()、values()、entries() 遍历数组方法,不改变原数组。 (es6 新增方法)
const arr = ["a", "b", "c", "d"];
for (let i of arr.entries()) {
console.log(i);
}
//打印:
// [0, "a"]
// [1, "b"]
// [2, "c"]
// [3, "d"]
for (let [idx, item] of arr.entries()) {
console.log(idx + ":" + item);
}
//打印:
// 0:a
// 1:b
// 2:c
// 3:d
- Array.from() (es6 新增方法)
Array.from() 用于类似数组的对象(即有 length 属性的对象)和可遍历对象转为真正的数组。
const json = {
0: "喜",
1: "欢",
2: "你",
length: 3,
};
const arr = Array.from(json);
console.log(arr); // ["喜", "欢", "你"]
- includes() 不改变原数组。 (es6 新增方法)
arr.includes(searchElement , fromIndex) 用来判断一个数组是否包含一个指定的值,如果是返回 true,否则 false。
const arr = ["a", "b", "c", "d"];
const result1 = arr.includes("b");
const result2 = arr.includes("b", 2);
const result3 = arr.includes("b", -1);
const result4 = arr.includes("b", -3);
console.log(result1); // true
console.log(result2); // false
console.log(result3); // flase
console.log(result4); // true
- reduce()、reduceRight() 归并方法,不改变原数组
这两个方法都会迭代数组中的所有项,然后生成一个最终返回值。他们都接收两个参数,第一个参数是每一项调用的函数,函数接受四个参数分别是初始值,当前值,索引值,和当前数组,函数需要返回一个值,这个值会在下一次迭代中作为初始值。第二个参数是迭代初始值,参数可选,如果缺省,初始值为数组第一项,从数组第一个项开始叠加,缺省参数要比正常传值少一次运算。
[total] 必须项,初始值, 或者计算结束后的返回值。
[cur] 必须项,当前元素。
[index] 可选。当前元素的索引值
[arr] 可选。当前元素所属的数组对象
[initialValue] 可选。传递给函数的初始值。
arr.reduce((total , cur , index , arr) => {}, initialValue) 从数组的第一项开始,逐个遍历到最后
arr.reduceRight((total , cur , index , arr) => {}, initialValue) 从数组的最后一项开始,向前遍历到第一项
ES2017(ES8)
- Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历属性的键值对数组。
const obj = {
name: "jimmy",
age: 18,
height: 188,
};
console.log(Object.entries(obj)); // [ [ 'name', 'jimmy' ], [ 'age', 18 ], [ 'height', 188 ] ]
console.log(Object.entries([1, 2, 3])); // [ [ '0', 1 ], [ '1', 2 ], [ '2', 3 ] ]
- String.prototype.padStart
把指定字符串填充到字符串头部,返回新字符串。
'abc'.padStart(10); // " abc"
'abc'.padStart(10, "foo"); // "foofoofabc"
'abc'.padStart(6,"123465"); // "123abc"
'abc'.padStart(8, "0"); // "00000abc"
'abc'.padStart(1); // "abc"
// 应用场景:
// 数字替换(手机号,银行卡号等)
const tel = '18781268679'
const newTel = tel.slice(-4).padStart(tel.length, '*')
console.log(newTel) // *******5678
ES2018(ES9)
- Object Rest
Object rest 的示例:
const input = {
a: 1,
b: 2,
c: 3
}
let { a, ...rest } = input
console.log(a, rest) // 1 {b: 2, c: 3}
// 当对象 key-value 不确定的时候,把必选的 key 赋值给变量,用一个变量收敛其他可选的 key 数据,这在之前是做不到的。注意,rest 属性必须始终出现在对象的末尾,否则将抛出错误。
- for await of
异步迭代器(for-await-of):循环等待每个 Promise 对象变为 resolved 状态才进入下一步。
我们知道 for…of 是同步运行的,看如下代码
function TimeOut(time){
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for (let item of arr) {
console.log(Date.now(),item.then(console.log))
}
}
test()
// 上述代码证实了 for of 方法不能遍历异步迭代器,得到的结果并不是我们所期待的,于是 for await of 就粉墨登场啦!
// ES9 中可以用 for...await...of 的语法来操作
function TimeOut(time) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(time)
}, time)
})
}
async function test() {
let arr = [TimeOut(2000), TimeOut(1000), TimeOut(3000)]
for await (let item of arr) {
console.log(Date.now(), item)
}
}
test()
// 1560092345730 2000
// 1560092345730 1000
// 1560092346336 3000
// for await of 环等待每个Promise对象变为resolved状态才进入下一步。所有打印的结果为 2000,1000,3000
- Promise.prototype.finally()
Promise.prototype.finally() 方法返回一个 Promise,在 promise 执行结束时,无论结果是 fulfilled 或者是 rejected,在执行 then()和 catch()后,都会执行 finally 指定的回调函数。这为指定执行完 promise 后,无论结果是 fulfilled 还是 rejected 都需要执行的代码提供了一种方式,避免同样的语句需要在 then()和 catch()中各写一次的情况。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
// reject('fail')
}, 1000)
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}).finally(() => {
console.log('finally')
})
// 使用场景
// loading关闭
// 需要每次发送请求,都会有loading提示,请求发送完毕,就需要关闭loading提示框,不然界面就无法被点击。不管请求成功或是失败,这个loading都需要关闭掉,这时把关闭loading的代码写在finally里再合适不过了
ES2019(ES10)
*Object.fromEntries()
方法 Object.fromEntries() 把键值对列表转换为一个对象,这个方法是和 Object.entries() 相对的。
Object.fromEntries([
['foo', 1],
['bar', 2]
])
// {foo: 1, bar: 2}
// 案例1:Object 转换操作
const obj = {
name: 'jimmy',
age: 18
}
const entries = Object.entries(obj)
console.log(entries)
// [Array(2), Array(2)]
// ES10
const fromEntries = Object.fromEntries(entries)
console.log(fromEntries)
// {name: "jimmy", age: 18}
// 案例2:Map 转 Object
const map = new Map()
map.set('name', 'jimmy')
map.set('age', 18)
console.log(map) // {'name' => 'jimmy', 'age' => 18}
const obj = Object.fromEntries(map)
console.log(obj)
// {name: "jimmy", age: 18}
// 案例3:过滤
// course表示所有课程,想请求课程分数大于80的课程组成的对象:
const course = {
math: 80,
english: 85,
chinese: 90
}
const res = Object.entries(course).filter(([key, val]) => val > 80)
console.log(res) // [ [ 'english', 85 ], [ 'chinese', 90 ] ]
console.log(Object.fromEntries(res)) // { english: 85, chinese: 90 }
// 案例4:url的search参数转换
// let url = "https://www.baidu.com?name=jimmy&age=18&height=1.88"
// queryString 为 window.location.search
const queryString = "?name=jimmy&age=18&height=1.88";
const queryParams = new URLSearchParams(queryString);
const paramObj = Object.fromEntries(queryParams);
console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }
*Array.prototype.flat()
let newArray = arr.flat([depth])
depth 可选 指定要提取嵌套数组的结构深度,默认值为 1。
flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat()); // [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2)); // [0, 1, 2, [3, 4]]
//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// `flat()` 方法会移除数组中的空项:
var arr5 = [1, 2, , 4, 5];
arr5.flat(); // [1, 2, 4, 5]
*Array.prototype.flatMap()
flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。从方法的名字上也可以看出来它包含两部分功能一个是 map,一个是 flat(深度为 1)。
const numbers = [1, 2, 3]
numbers.map(x => [x * 2]) // [[2], [4], [6]]
numbers.flatMap(x => [x * 2]) // [2, 4, 6]
// 这个示例可以简单对比下 map 和 flatMap 的区别。当然还可以看下下面的示例:
let arr = ['今天天气不错', '', '早上好']
arr.map(s => s.split(''))
// [["今", "天", "天", "气", "不", "错"],[""],["早", "上", "好"]]
arr.flatMap(s => s.split(''))
// ["今", "天", "天", "气", "不", "错", "", "早", "上", "好"]
// flatMap 方法与 map 方法和深度depth为1的 flat 几乎相同.
*String.prototype.trimStart()
trimStart() 方法从字符串的开头删除空格,trimLeft()是此方法的别名。
let str = ' foo '
console.log(str.length) // 8
str = str.trimStart() // 或str.trimLeft()
console.log(str.length) // 5
*可选的 Catch Binding
在 ES10 之前我们都是这样捕获异常的:
try {
// tryCode
} catch (err) {
// catchCode
}
// 在这里 err 是必须的参数,在 ES10 可以省略这个参数:
try {
console.log('Foobar')
} catch {
console.error('Bar')
}
// 应用
// 验证参数是否为json格式
// 这个需求我们只需要返回true或false,并不关心catch的参数。
const validJSON = json => {
try {
JSON.parse(json)
return true
} catch {
return false
}
}
ES2020(ES11)
*可选链操作符( ?. )
?. 操作符的功能类似于 . 链式操作符,不同之处在于,在引用为 null 或者 undefined 的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用时,如果给定的函数不存在,则返回 undefined。
*空值合并运算符(Nullish coalescing Operator)
空值合并操作符( ?? )是一个逻辑操作符,当左侧的操作数为 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数。
与空值合并操作符一起使用;
let customer = {
name: "jimmy",
details: { age: 18 },
};
let customerCity = customer?.city ?? "成都";
console.log(customerCity); // "成都"
const foo = undefined ?? "foo"
const bar = null ?? "bar"
console.log(foo) // foo
console.log(bar) // bar
*Promise.allSettled()
我们都知道 Promise.all() 具有并发执行异步任务的能力。但它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise 直接进入 reject 状态。
场景:现在页面上有三个请求,分别请求不同的数据,如果一个接口服务异常,整个都是失败的,都无法渲染出数据
我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态,这就是 Promise.allSettled 的作用
const promise1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise1");
// reject("error promise1 ");
}, 3000);
});
};
const promise2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise2");
// reject("error promise2 ");
}, 1000);
});
};
const promise3 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("promise3");
reject("error promise3 ");
}, 2000);
});
};
// Promise.all 会走到catch里面
Promise.all([promise1(), promise2(), promise3()])
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log("error", error); // error promise3
});
// Promise.allSettled 不管有没有错误,三个的状态都会返回
Promise.allSettled([promise1(), promise2(), promise3()])
.then((res) => {
console.log(res);
// 打印结果
// [
// {status: 'fulfilled', value: 'promise1'},
// {status: 'fulfilled',value: 'promise2'},
// {status: 'rejected', reason: 'error promise3 '}
// ]
})
.catch((error) => {
console.log("error", error);
});
*import()可以在需要的时候,再加载某个模块。
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
ES2021(ES12)
*&&=
// 逻辑与赋值 x &&= y等效于:
x && (x = y);
// 上面的意思是,当x为真时,x=y。
// 具体请看下面的示例:
let a = 1;
let b = 0;
a &&= 2;
console.log(a); // 2
b &&= 2;
console.log(b); // 0
*||=
逻辑或赋值(x ||= y)运算仅在 x 为false时赋值。
x ||= y 等同于: x || (x = y);
const a = { duration: 50, title: '' };
a.duration ||= 10;
console.log(a.duration); // 50
a.title ||= 'title is empty.';
console.log(a.title); // "title is empty"
*??=
逻辑空赋值运算符 (x ??= y) 仅在 x 是 nullish[3] (null 或 undefined) 时对其赋值。
x ??= y 等价于:x ?? (x = y);
const a = { duration: 50 };
a.duration ??= 10;
console.log(a.duration); // 50
a.speed ??= 25;
console.log(a.speed); // 25
function config(options) {
options.duration ??= 100;
options.speed ??= 25;
return options;
}
config({ duration: 125 }); // { duration: 125, speed: 25 }
config({}); // { duration: 100, speed: 25 }
*String.prototype.replaceAll()
replaceAll() 方法返回一个新字符串,新字符串中所有满足 pattern 的部分都会被 replacement 替换。pattern 可以是一个字符串或一个 RegExp,replacement 可以是一个字符串或一个在每次匹配被调用的函数。
原始字符串保持不变。
'aabbcc'.replaceAll('b', '.'); // 'aa..cc'
// 使用正则表达式搜索值时,它必须是全局的。
// 'aabbcc'.replaceAll(/b/, '.');
// TypeError: replaceAll must be called with a global RegExp
这将可以正常运行:
'aabbcc'.replaceAll(/b/g, '.');
"aa..cc"
*Promise.any
方法接受一组 Promise 实例作为参数,包装成一个新的 Promise 实例返回。
const promise1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise1");
// reject("error promise1 ");
}, 3000);
});
};
const promise2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise2");
// reject("error promise2 ");
}, 1000);
});
};
const promise3 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("promise3");
// reject("error promise3 ");
}, 2000);
});
};
Promise.any([promise1(), promise2(), promise3()])
.then((first) => {
// 只要有一个请求成功 就会返回第一个请求成功的
console.log(first); // 会返回promise2
})
.catch((error) => {
// 所有三个全部请求失败 才会来到这里
console.log("error", error);
});
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。