久经沙场的前辈们,写了有数代码,踩了有数的坑。但有些坑,可能一辈子也踩不到摸不着,因为基本不会产生在业务代码里~~
1
Function.prototype 居然是个函数类型。而自定义函数的原型却是对象类型。
typeof Function.prototype === 'function'; // true
const People() {}
typeof People.prototype === 'object'; // true
所以咱们设置空函数能够这么做:
// Good
const noop = Function.prototype;
// Bad
const noop = () => {};
2
一个变量真的会不等于本身吗?
const x = NaN;
x !== x // true
这是目前为止 js 语言中惟一的一个不等于本人的数据。为什么?因为 NaN 代表的是一个范畴,而不是一个具体的数值。
在晚期的 isNaN() 函数中,即便传入字符串,也会返回 true,这个问题曾经在 es6 中修复。
isNaN('abc'); // true
Number.isNaN('abc') // false
所以如果您想兼容旧浏览器,用 x !== x 来判断是不是 NaN,是一个不错的计划。
3
构造函数如果 return 了新的数据
// 不返回
const People() {}
const people = new People(); // People {}
// 返回数字
const People() {return 1;}
const people = new People(); // People {}
// 返回新对象
const Animal() {
return {hello: 'world',};
}
const animal = new Animal(); // { hello: 'world'}
在实例化构造函数时,返回 非对象 类型将不失效
4
.call.call 到底在为谁疯狂打 call?
function fn1() {console.log(1);
}
function fn2() {console.log(2);
}
fn1.call.call(fn2); // 2
所以 fn1.call.call(fn2) 等效于 fn2.call(undefined)
。而且无论您加多少个 .call,成果也是一样的。
5
实例后的对象也能再次实例吗?
function People() {}
const lili = new People(); // People {}
const lucy = new tom.constructor(); // People {}
因为 lili 的 原型链 指向了 People 的原型,所以通过向上寻找个性,最终在 Peopel.prototype 上找到了结构器即 People 本身
6
setTimeout 嵌套会产生什么奇怪的事件?
console.log(0, Date.now());
setTimeout(() => {console.log(1, Date.now());
setTimeout(() => {console.log(2, Date.now());
setTimeout(() => {console.log(3, Date.now());
setTimeout(() => {console.log(4, Date.now());
setTimeout(() => {console.log(5, Date.now());
setTimeout(() => {console.log(6, Date.now());
});
});
});
});
});
});
在 0 - 4 层,setTimeout 的距离是 1ms,而到第 5 层时,距离至多是 4ms。
7
es6 函数带默认参数时将生成 申明作用域
var x = 10;
function fn(x = 2, y = function () {return x + 1}) {
var x = 5;
return y();}
fn(); // 3
8
函数表达式(非函数申明)中的函数名不可笼罩
const c = function CC() {
CC = 123;
return CC;
};
c(); // Function
当然,如果设置var CC = 123
,加申明关键词是能够笼罩的。
9
严格模式下,函数的 this 是 undefined 而不是 Window
// 非严格
function fn1() {return this;}
fn1(); // Window
// 严格
function fn2() {
'use strict';
return this;
}
fn2(); // undefined
对于模块化的通过 webpack 打包的代码,根本都是严格模式的代码。
10
取整操作也能够用按位操作
var x = 1.23 | 0; // 1
因为按位操作只反对 32 位的整型,所以小数点局部全副都被摈弃
11
indexOf() 不须要再比拟数字
const arr = [1, 2, 3];
// 存在,等效于 > -1
if (~arr.indexOf(1)) {
}
// 不存在,等效于 === -1
!~arr.indexOf(1);
按位操作效率高点,代码也简洁一些。也能够应用 es6 的 includes()。但写开源库须要思考兼容性的道友还是用 indexOf 比拟好
12
getter/setter 也能够动静设置吗?
class Hello {
_name = 'lucy';
getName() {return this._name;}
// 动态的 getter
get id() {return 1;}
}
const hel = new Hello();
hel.name; // undefined
hel.getName(); // lucy
// 动静的 getter
Hello.prototype.__defineGetter__('name', function() {return this._name;});
Hello.prototype.__defineSetter__('name', function(value) {this._name = value;});
hel.name; // lucy
hel.getName(); // lucy
hel.name = 'jimi';
hel.name; // jimi
hel.getName(); // jimi
13
0.3 - 0.2 !== 0.1 // true
14
class 语法糖到底是怎么继承的?
function Super() {this.a = 1;}
function Child() {
// 属性继承
Super.call(this);
this.b = 2;
}
// 原型继承
Child.prototype = new Super();
const child = new Child();
child.a; // 1
正式代码的原型继承,不会间接实例父类,而是实例一个空函数,防止反复申明动静属性
const extends = (Child, Super) => {const fn = function () {};
fn.prototype = Super.prototype;
Child.prototype = new fn();
Child.prototype.constructor = Child;
};
15
脑袋空了,收集中,可遇不可求。。。