以下的知识点 相对来说有点散,为文档笔记!
怎么判断一个变量是 NaN
var v = NaN
isNaN(v) // true 但是 isNaN函数会首先尝试将这个参数转换为数值,然后才会对转换后的结果是否是NaN进行判断
// 举个🌰
isNaN('string') // true oops!
// 升级不转换类型
Number.isNaN(v) // true
// 或者
Object.is(v, NaN) // true
// 利用自身的特点
v !== v // true
怎么判断变量是 +0 还是 -0
var zero
// 直接api
Object.is(zero, 0)
// 利用自身特性
1 / zero // zero 若是 +0 则是 Infinity 否则是 -Infinity
上面的两个判断 都提及了 Object.is() 手动实现一波
if (!Object.is) {
Object.is = function (x, y) {
if (x === 0) {
return 1 / x === 1 / y;
} else if (x !== x) { // 判断 NaN
return y !== y;
}
return x === y;
};
}
base64 转码
JavaScript 原生提供两个 Base64 相关的方法。
- btoa():任意值转为 Base64 编码
- atob():Base64 编码转为原来的值
var string = 'Hello World!';
btoa(string) // "SGVsbG8gV29ybGQh"
atob('SGVsbG8gV29ybGQh') // "Hello World!"
如果是非 ASCII 码字符转为 Base64 编码, 则需要进行转码
btoa('你好') // error
// 需要转码
btoa(encodeURIComponent('你好')) // "JUU0JUJEJUEwJUU1JUE1JUJE"
decodeURIComponent(atob('JUU0JUJEJUEwJUU1JUE1JUJE')) // "你好"
借用函数输出字符串
(function () { /*
line 1
line 2
line 3
*/}).toString().split('\n').slice(1, -1).join('\n')
// "line 1
// line 2
// line 3"
函数的同名参数, 参数名都是a。取值的时候,以后面的a为准,即使后面的a没有值或被省略,也是以其为准
function f(a, a) {
console.log(a); // undefined
// 为了 取到第一个的值咋办呢 使用 arguments
console.log(arguments[0]) // 1
}
f(1)
位运算符的几个小点 交换位置 取整
// 交换
var a = 1, b = 2
a ^= b
b ^= a
a ^= b
a // 2
b // 1
// 取整 (据说是最快取整) (直接 去掉小数点后面的值)
~~1.8 // 1
~~1.2 // 1
~~-1.2 // -1
~~-1.8 // -1
// 插播一道题
// 描述: 又一个数组(arr) 有偶数个(至少两个)a, 以及其他单个数值 b, 找出b
// var arr = [1, 1, 2, 1, 1] (返回 2) 或者 arr = [2, 2, 1] (返回 1) 或者 arr =[4, 4, 4, 4, 5] (返回 5)
// 法一
// 不太优雅
function find(arr) {
let obj = {}
arr.forEach((item) => obj[item] ? obj[item] ++ : obj[item] = 1)
return +Object.entries(obj).filter(([key, value]) => value == 1)[0][0]
}
// 法二
// 就两种数值
function find(arr) {
arr.sort((a, b) => a - b);
return arr[0] == arr[1] ? arr[arr.length - 1] : arr[0];
}
// 法三
// 优雅
function find(arr) {
return arr.reduce((acc, cur) => acc ^ cur);
}
console.log() 的一些占位符 不同类型的数据必须使用对应的占位符
* %s 字符串
* %d 整数
* %i 整数
* %f 浮点数
* %o 对象的链接
* %c CSS 格式字符串
// 举个🌰
var s = 'string',
int = 1,
i = 2,
f = 2.2,
o = {name: 'hello'},
c = 'color: lightblue;'
console.log('%c hello world %s, %d, %i, %f, %o',c, s, int, i, f, o)
判断一个变量是否是对象 可以使用 Object()
value === Object(value) // 若是是对象则为 true
对空数组使用pop方法,不会报错,而是返回undefined
console.log([].pop()) // undefined
字符串的一些注意点
- 如果参数为负数,或大于等于字符串的长度,charCodeAt返回NaN
- split方法还可以接受第二个参数,限定返回数组的最大成员数
'abc'.charCodeAt(-1) // NaN
'abc'.charCodeAt(4) // NaN
'a|b|c'.split('|', 0) // []
'a|b|c'.split('|', 1) // ["a"]
'a|b|c'.split('|', 2) // ["a", "b"]
'a|b|c'.split('|', 3) // ["a", "b", "c"]
'a|b|c'.split('|', 4) // ["a", "b", "c"]
Date 的一些可以注意的点
- 无论有没有参数,直接调用Date总是返回当前时间
- Date.prototype.toLocaleDateString():本地日期 "2020/9/22"
- d2.setDate(-1)表示设为上个月的倒数第二天,即12月30日
Date() // "Wed Sep 23 2020 "
Date('s') // "Wed Sep 23 2020 "
Date(NaN) // "Wed Sep 23 2020 "
// 返回的是数字的年月日
new Date().toLocaleDateString() // "2020/9/23"
// setDate 的具体表现
var d = new Date ();
d // Wed Sep 23 2020
d.setDate(-1) // 1598779043121
d // Sun Aug 30 2020
JSON.parse方法可以接受一个处理函数,作为第二个参数
function f(key, value) {
if (key === 'a') {
return value + 10;
}
return value;
}
JSON.parse('{"a": 1, "b": 2}', f)
// {a: 11, b: 2}
call方法的参数,应该是一个对象。如果参数为空、null和undefined,则默认传入全局对象,apply参数为空、null和undefined,则默认传入全局对象
var n = 123
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
另类的对象拷贝
function copyObject(orig) {
return Object.create(
Object.getPrototypeOf(orig),
Object.getOwnPropertyDescriptors(orig)
);
}
异步操作的流程控制
// 串行执行
var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];
function async(arg, callback) {
console.log('参数为 ' + arg +' , 1秒后返回结果');
setTimeout(function () { callback(arg * 2); }, 1000);
}
function final(value) {
console.log('完成: ', value);
}
function series(item) {
if(item) {
async( item, function(result) {
results.push(result);
return series(items.shift());
});
} else {
return final(results[results.length - 1]);
}
}
series(items.shift());
// 并行执行
var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];
function async(arg, callback) {
console.log('参数为 ' + arg +' , 1秒后返回结果');
setTimeout(function () { callback(arg * 2); }, 1000);
}
function final(value) {
console.log('完成: ', value);
}
items.forEach(function(item) {
async(item, function(result){
results.push(result);
if(results.length === items.length) {
final(results[results.length - 1]);
}
})
});
var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];
var running = 0;
var limit = 2;
function async(arg, callback) {
console.log('参数为 ' + arg +' , 1秒后返回结果');
setTimeout(function () { callback(arg * 2); }, 1000);
}
function final(value) {
console.log('完成: ', value);
}
function launcher() {
while(running < limit && items.length) {
var item = items.shift();
async(item, function(result) {
results.push(result);
running--;
if(items.length) {
launcher();
} else if(!running) {
final(results);
}
});
running++;
}
}
launcher();
定时器的一些点
- setTimeout的第二个参数如果省略,则默认为0。
- setTimeout的参数。从第三个参数起,将在1000毫秒之后回调函数执行时,作为回调函数的参数
- 生效后setInterval不会产生累积效应,即不会一下子执行多次,而是只会执行一次
setTimeout(f) // 等同于 setTimeout(f, 0)
function f(a, b, c, d) {
console.log(a, b, c, d) // 1, 2, 3 ,4
}
setTimeout(f, 1000, 1, 2, 3, 4)
// 对应上方第三点
setInterval(function () {
console.log(2);
}, 1000);
sleep(3000);
function sleep(ms) {
var start = Date.now();
while ((Date.now() - start) < ms) {
}
}
最后
以上的知识点来自 网道 的 从入门篇部分到异步操作部分 的梳理,常看常新。