Javascript中的奇葩知识,你知道吗?


Posted in Javascript onJanuary 25, 2021

久经沙场的前辈们,写了无数代码,踩了无数的坑。但有些坑,可能一辈子也踩不到摸不着,因为根本不会发生在业务代码里~~

1

Function.prototype 竟然是个函数类型。而自定义函数的原型却是对象类型。

typeof Function.prototype === 'function'; // true

function People() {}
typeof People.prototype === 'object';   // true

所以我们设置空函数可以这么做:

// OK 
const noop = Function.prototype;
// OK
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了新的数据

// 不返回
function People() {}
const people = new People();  // People {}

// 返回数字
function People() {
 return 1;
}
const people = new People();  // People {}

// 返回新对象
function 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 lili.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

浮点操作不精确,老生常谈了,不过可以接受误差

0.3 - 0.2 - 0.1 <= Number.EPSILON // 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

es6居然可以重复解构对象

const obj = {
 a: {
  b: 1
 },
 c: 2
};

const { a: { b }, a } = obj;

一行代码同时获取a和a.b。
在a和b都要多次用到的情况下,普通人的逻辑就是先解构出a,再在下一行解构出b。

16

判断代码是否压缩居然也这么秀

function CustomFn() {}

const isCrashed = typeof CustomFn.name === 'string' && CustomFn.name === 'CustomFn';

17

对象===比较的是内存地址,而>=将比较转换后的值

{} === {} // false

// 隐式转换 toString()
{} >= {} // true

18

intanceof 的判断方式是原型是否在当前对象的原型链上面

function People() {}
function Man() {}
Man.prototype = new People();
Man.prototype.constructor = Man;

const man = new Man();
man instanceof People;  // true

// 替换People的原型
People.prototype = {};
man instanceof People;  // false

如果您用es6的class的话,prototype原型是不允许被重新定义的,所以不会出现上述情况

19

Object.prototype.__proto__ === null; // true

这是原型链向上查找的最顶层,一个null

20

parseInt太小的数字会产生bug

parseInt(0.00000000454); // 4
parseInt(10.23);     // 10

21

1 + null     // 1
1 + undefined   // NaN

Number(null)   // 0
Number(undefined) // NaN

22

实参arguments和形参会保持同步关系

function test(a, b, c) {
 console.log(a, b, c); // 2, 3, undefined
 
 arguments[0] = 100;
 arguments[1] = 200;
 arguments[2] = 300;
 
 console.log(a, b, c); // 100, 200, undefined
}
test(2, 3);

如果实参传的个数不足,那么同步关系也会失效。
您也可以用use strict严格模式来避免这一行为,这样arguments就只是个副本了。

23

void是个固执的老头

void 0 === undefined     // true
void 1 === undefined     // true
void {} === undefined     // true
void 'hello' === undefined  // true
void void 0 === undefined   // true

跟谁都不沾亲~~

24

try/catch/finally也有特定的执行顺序

function fn1() {
 console.log('fn1');
 return 1;
}

function fn2() {
 console.log('fn2');
 return 2;
}

function getData() {
 try {
  throw new Error('');
 } catch (e) {
  return fn1();
 } finally {
  return fn2();
 }
}

console.log(getData());

// 打印顺序: 'fn1', 'fn2', 2

在try/catch代码块中,如果碰到return xxyyzz;关键词,那么xxyyzz会先执行并把值放在临时变量里,接着去执行finally代码块的内容后再返回该临时变量。
如果finally中也有return aabbcc,那么会立即返回新的数据aabbcc。

25

是否存在这样的变量x,使得它等于多个数字?

const x = {
 value: 0,
 toString() {
  return ++this.value;
 }
}

x == 1 && x == 2 && x == 3;  // true

通过隐式转换,这样不是什么难的事情。

26

clearTimeout 和 clearInterval 可以互换使用吗

var timeout = setTimeout(() => console.log(1), 1000);
var interval = setInterval(() => console.log(2), 800);

clearInterval(timeout);
clearTimeout(interval);

答案是:YES。大部分浏览器都支持互相清理定时器,但是建议使用对应的清理函数。

27

下面的打印顺序是?

setTimeout(() => {
 console.log(1);
}, 0);

new Promise((resolve) => {
 console.log(2);
 resolve();
}).then(() => console.log(3));

function callMe() {
 console.log(4);
}

(async () => {
 await callMe();
 console.log(5);
})();

答案是:2, 4, 3, 5, 1

主线任务:2,4
微任务:3,5
宏任务:1

28

null是object类型,但又不是继承于Object,它更像一个历史遗留的bug。鉴于太多人在用这个特性,修复它反而会导致成千上万的程序出错。

typeof null === 'object';       // true
Object.prototype.toString.call(null); // [object Null]
null instanceof Object;        // false

29

基本类型(null和undefined除外)在操作的时候,引擎会自动为数据包装成对象,操作完就销毁对象。

'abc'.substr(1);
(123).toFixed(2);

所以增加任何数据上去都会被销毁,除非修改原型链

const data = 'abc';
data.x = 'y';
console.log(data.x); // undefined

data.__proto__.x = 'z';
console.log(data.x); // 'z'

30

数据超过了安全值就变得不安全了

Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2; // true

// 等价于
2 ** 53 === 2 ** 53 + 1;   // true

31

函数形参带默认值时,会改变一些认知

function test(a, b = 1) {
 // 别名同步,非严格模式预期可以同步
 arguments[0] = 20;
 console.log(a);      // 2
}
// 检测函数的形参个数,预期值为:2
console.log(test.length);  // 1

test(123);

32

数字都是浮点类型。位运算操作时,js会先把数字转换到int类型。相对于其他语言,这算是一笔额外的性能开销。

1 | 0      // 1
1.234 | 0    // 1
1.234 | 0.6   // 1

1 & 1      // 1
1.23 & 1.456  // 1

~1       // -2
~1.234     // -2

33

赋值给location可以直接跳转

location = 'http://baidu.com';

34

你知道new的另一个用法吗?

function Test() {
 console.log(new.target === Test); // true
}

new Test();

如果实例了子类,那么new.target就不是Test了,通过这个方法可以实现abstract class的效果

35

+0 和 -0 是有区别的

1/+0 === Infinity
1/-0 === -Infinity

以上就是Javascript中的奇葩知识,你知道吗?的详细内容,更多关于JavaScript 奇葩知识的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
学习js所必须要知道的一些
Mar 07 Javascript
JavaScript 入门基础知识 想学习js的朋友可以参考下
Dec 26 Javascript
jquery获取div距离窗口和父级dv的距离示例
Oct 10 Javascript
js判断undefined类型,undefined,null, 的区别详细解析
Dec 16 Javascript
javascript中的return和闭包函数浅析
Jun 06 Javascript
很不错的两款Bootstrap Icon图标选择组件
Jan 28 Javascript
JavaScript的==运算详解
Jul 20 Javascript
js利用clipboardData实现截屏粘贴功能
Oct 12 Javascript
HTML5canvas 绘制一个圆环形的进度表示实例
Dec 16 Javascript
教你5分钟学会用requirejs(必看篇)
Jul 25 Javascript
vue.js  父向子组件传参的实例代码
Oct 29 Javascript
vue axios重复点击取消上一次请求封装的方法
Jun 19 Javascript
vue 计算属性和侦听器的使用小结
Jan 25 #Vue.js
JavaScript中clientWidth,offsetWidth,scrollWidth的区别
Jan 25 #Javascript
vue keep-alive的简单总结
Jan 25 #Vue.js
JS实现简易日历效果
Jan 25 #Javascript
javascript代码实现简易计算器
Jan 25 #Javascript
js简单粗暴的发布订阅示例代码
Jan 23 #Javascript
JS中循环遍历数组的四种方式总结
Jan 23 #Javascript
You might like
PHP 和 MySQL 基础教程(二)
2006/10/09 PHP
模板引擎正则表达式调试小技巧
2011/07/20 PHP
PHP 数组和字符串互相转换实现方法
2013/03/26 PHP
PHP会话处理的10个函数
2015/08/11 PHP
linux平台编译安装PHP7并安装Redis扩展与Swoole扩展实例教程
2016/09/30 PHP
JS 学习笔记 防止发生命名冲突
2009/07/30 Javascript
如何让div span等元素能响应键盘事件操作指南
2012/11/13 Javascript
innerHTML属性,outerHTML属性,textContent属性,innerText属性区别详解
2015/03/13 Javascript
jquery如何获取元素的滚动条高度等实现代码
2015/10/19 Javascript
JavaScript学习笔记整理之引用类型
2016/01/22 Javascript
jQuery.ajax实现根据不同的Content-Type做出不同的响应
2016/11/03 Javascript
javascript入门之window对象【新手必看】
2016/11/22 Javascript
Webpack中css-loader和less-loader的使用教程
2017/04/27 Javascript
浅谈Node.js轻量级Web框架Express4.x使用指南
2017/05/03 Javascript
JavaScript使用prototype原型实现的封装继承多态示例
2018/08/31 Javascript
this在vue和小程序中的使用详解
2019/01/28 Javascript
[03:58]兄弟们,回来开黑了!DOTA2昔日战友招募宣传视频
2016/07/17 DOTA
[48:38]DOTA2亚洲邀请赛 3.31 小组赛 B组 Mineski vs Secret
2018/03/31 DOTA
Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】
2017/09/28 Python
浅谈python新式类和旧式类区别
2019/04/26 Python
Python 异常的捕获、异常的传递与主动抛出异常操作示例
2019/09/23 Python
python 利用pyttsx3文字转语音过程详解
2019/09/25 Python
Python使用grequests(gevent+requests)并发发送请求过程解析
2019/09/25 Python
Pyqt5自适应布局实例
2019/12/13 Python
Python3 ID3决策树判断申请贷款是否成功的实现代码
2020/05/21 Python
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢?
2016/08/18 面试题
最新的互联网创业计划书
2014/01/10 职场文书
网络技术专业求职信
2014/02/18 职场文书
职业生涯规划书结束语
2014/04/15 职场文书
精彩的演讲稿开头
2014/05/08 职场文书
2014年学校总务处工作总结
2014/12/08 职场文书
企业财务人员岗位职责
2015/04/14 职场文书
2015社区爱国卫生工作总结
2015/04/21 职场文书
酒店厨房管理制度
2015/08/06 职场文书
浅析Redis Sentinel 与 Redis Cluster
2021/06/24 Redis
使用goaccess分析nginx日志的详细方法
2021/07/09 Servers