Javascript 裏的奇葩知識

久經沙場的前輩們,寫了無數代碼,踩了無數的坑。但有些坑,可能一生也踩不到摸不着,由於根本不會發生在業務代碼裏~~javascript

1

Function.prototype 居然是個函數類型。而自定義函數的原型倒是對象類型。java

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

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

因此咱們設置空函數能夠這麼作:webpack

// Good 
const noop = Function.prototype;

// Bad
const noop = () => {};

2

一個變量真的會不等於自身嗎?es6

const x = NaN;
x !== x  // true

這是目前爲止js語言中惟一的一個不等於本身的數據。爲何?由於NaN表明的是一個範圍,而不是一個具體的數值。
在早期的 isNaN() 函數中,即便傳入字符串,也會返回true,這個問題已經在es6中修復。web

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?oop

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

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

fn1.call.call(fn2); // 2

因此 fn1.call.call(fn2) 等效於 fn2.call(undefined)。並且不管您加多少個 .call,效果也是同樣的。this

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

腦殼空了,收集中,可遇不可求。。。

相關文章
相關標籤/搜索