JS学习日常所得
查 filter 的时候看到关于去重的三种方式
var arrS = [1, 2, 3, 4, 5, 5, 5, 8, 8, 2, 3, 9, 4, 1, 2, 'a', 'a', 'c', 'd'];
var resF = arrS.filter(function (item, idx, arr) {
return arr.indexOf(item) === idx;
});
//这个去重明显是依赖indexOf,跟filter关系不大吧
console.log(resF);
//数组[]数字还是数字,字符串还是字符串
var arrSet = new Set(arrS);
console.log(arrSet);
//set{}数字还是数字,字符串还是字符串
var obj = {};
arrS.forEach(function (item) { obj[item] = item });
// keys 返回所有可枚举属性的字符串数组
console.log(Object.keys(obj));
//数组[]全部是字符串
filter结合map做数据筛选的方式,评论提到性能问题,有些认同,但没有测试
一个很*&&……%¥的面试题
can (a==1 && a==2 && a==3) ever evaluate to true
有意思的是
a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);
最高赞同解
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
这里toString
等同于valueOf
由此看到宽松相等
[] == ![]
解释如下:
- 等号右边有!,优先级比==高,先计算右边结果;
- []为非假值,false;
- ==任意一边有boolean,,将其转为number,右边变成0;
-
==两边为object和boolean,将object转number
Number([].valueOf()) ==> 0
至此,等式成立.
然后发现
[] == []
返回false,以及
null == 0 >> false
null >= 0 >> true
null > 0 >> false
首先[]==[]
因为不是一个object,然后
因为==
和>=
,>
也就是相等运算符和关系运算符并不是一类:
关系运算符,在设计上,总是需要运算元尝试转为一个number,而相等运算符在设计上,则没有这方面的考虑
==
的规则是这个样子的:
1、当两个运算数的类型不同时,将它们转换成相同的类型:
1)一个数字与一个字符串,字符串转换成数字之后,进行比较.
2)true转换为1、false转换为0,进行比较.
3)一个对象、数组、函数 与 一个数字或字符串,对象、数组、函数转换为原始类型的值,然后进行比较(先使用valueOf,如果不行就使用toString).
2、当两个运算数类型相同,或转换成相同类型后:
1)2个字符串:同一位置上的字符相等,2个字符串就相同.
2)2个数字:2个数字相同,就相同.如果一个是NaN,或两个都是NaN,则不相同.
3)2个都是true,或者2个都是false,则相同.
4)2个引用的是同一个对象、函数、数组,则它们相等,如果引用的不是同一个对象、函数、数组,则不相同,即使这2个对象、函数、数组可以转换成完全相等的原始值.
5)2个null,或者2个都是未定义的,那么它们相等.
有表格版描述如下
被比较值 B | |||||||
---|---|---|---|---|---|---|---|
Undefined | Null | Number | String | Boolean | Object | ||
被比较值 A | Undefined | true |
true |
false |
false |
false |
IsFalsy(B) |
Null | true |
true |
false |
false |
false |
IsFalsy(B) |
|
Number | false |
false |
A === B |
A === ToNumber(B) |
A=== ToNumber(B) |
A=== ToPrimitive(B) |
|
String | false |
false |
ToNumber(A) === B |
A === B |
ToNumber(A) === ToNumber(B) |
ToPrimitive(B) == A |
|
Boolean | false |
false |
ToNumber(A) === B |
ToNumber(A) === ToNumber(B) |
A === B |
ToNumber(A) == ToPrimitive(B) | |
Object | false | false | ToPrimitive(A) == B |
ToPrimitive(A) == B |
ToPrimitive(A) == ToNumber(B) |
|
debounce&&throttling
感觉就是对settimeout和setinterval的封装
debounce
合并一段时间内的重复连续操作,如连续快速点击鼠标
throttle
只允许一个函数在x毫秒内执行一次(x毫秒内至少执行一次)
immediate
debounce的执行在一连串操作之后,immediate(leading)发生在一连串操作刚开始
现有封装好的库underscore/Lodash,Lodash支持自定义需要的函数生成压缩库
Promise例子
new Promise(function (resolve, reject) {
log('start new Promise...');
var timeOut = Math.random() * 2;
log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function () {
if (timeOut < 1) {
log('call resolve()...');
resolve('200 OK');
}
else {
log('call reject()...');
reject('timeout in ' + timeOut + ' seconds.');
}
}, timeOut * 1000);
}).then(function (r) {
log('Done: ' + r);
}).catch(function (reason) {
log('Failed: ' + reason);
});
就像ajax一样分离处理结果,然后还可以
job1.then(job2).then(job3).catch(handleError);
避免顺序执行的嵌套,然后针对容错race
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
console.log(result); // 'P1'
});
p1执行得快,p2虽然还在执行,但是结果将被抛弃
奇怪的面试题
- 引用和赋值
var foo = {n: 1}; // foo n1
var bar = foo; // bar === foo
// 0. foo,bar > x0A 赋值已经完成
foo.x = foo = {n: 2};
// 先计算左边 再计算右边 再赋值
// 1. foo.x > foo = x0A > foo n1 x
// 先计算左边 给之前的foo也就是foo-old一个x属性
// * 这里为新的x属性分配了内存空间x1C?但是并没有对x赋值
// 2. foo > x1B foo.x > x1B
// * 接着计算右边 foo-new被赋值x1B 于是x属性也就是x1C指向x1B 该行计算结束
// 3. bar指向 x0A没有改变过
// * x0A 该地址内是 n1 x:n2 x1B地址内是 n2 x2C地址内是 n2
console.log(foo.x); //undefined
console.log(bar.x); //{n:2}
- 形参和匿名函数
(function(x, f = () => x) {
// 首先这里给参数f默认赋值了一个匿名函数,由于作用域的关系,函数f是不能访问到函数内的x的
var x;
// 只进行了声明而没有赋值,所以在作用域链还会找到形参x
// 这里试了一下如果x有赋值比如5,y会被赋值成5
var y = x; // 这里y的值取的还是形参x的值
x = 2;
// 这里对上面的var x进行赋值而形参x的值是不受影响的console.log(arguments[0]试一下,所以f()返回是1,此时作用域链上会先找到函数内声明的x
return [x, y, f()]; // [2, 1, 1]
})(1);
(function(x, f = () => x) {
var y = x; // 这里只声明了y, x 还是形参x
x = 2; // 这里改变了形参x的值,所以 f() 返回是 2
return [x, y, f()]; // [2, 1, 2]
})(1)
默认参数可用于后面的默认参数,所以f可以获取前面的x形参但是不能访问到函数内部的x
[1]+[2]-[3] === 9
[1]+[2] //”12”
-[3] //-3
“12”-3 //9
以及发现
“123”*1 //123
Date
使用Date.parse()时传入的字符串使用实际月份01~12,转换为Date对象后getMonth()获取的月份值为0~11
JavaScript的Date对象月份值从0开始,牢记0=1月,1=2月,2=3月,……,11=12月.