<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JavaScript 里的奇葩知識(shí)

          共 5947字,需瀏覽 12分鐘

           ·

          2020-12-19 13:01



          授權(quán)轉(zhuǎn)載自:原罪?

          https://segmentfault.com/a/1190000023941089

          久經(jīng)沙場(chǎng)的前輩們,寫了無數(shù)代碼,踩了無數(shù)的坑。但有些坑,可能一輩子也踩不到摸不著,因?yàn)楦静粫?huì)發(fā)生在業(yè)務(wù)代碼里~~

          1

          Function.prototype 竟然是個(gè)函數(shù)類型。而自定義函數(shù)的原型卻是對(duì)象類型。

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

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

          所以我們?cè)O(shè)置空函數(shù)可以這么做:

          //?Good?
          const?noop?=?Function.prototype;

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

          2

          一個(gè)變量真的會(huì)不等于自身嗎?

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

          這是目前為止 js 語言中唯一的一個(gè)不等于自己的數(shù)據(jù)。為什么?因?yàn)?NaN 代表的是一個(gè)范圍,而不是一個(gè)具體的數(shù)值。 在早期的 isNaN() 函數(shù)中,即使傳入字符串,也會(huì)返回 true ,這個(gè)問題已經(jīng)在 es6 中修復(fù)。

          isNaN('abc');???????//?true
          Number.isNaN('abc')?//?false

          所以如果您想兼容舊瀏覽器,用 x !== x 來判斷是不是NaN,是一個(gè)不錯(cuò)的方案。

          3

          構(gòu)造函數(shù)如果 return了新的數(shù)據(jù)

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

          //?返回?cái)?shù)字
          function?People()?{
          ??return?1;
          }
          const?people?=?new?People();???//?People?{}

          //?返回新對(duì)象
          function?Animal()?{
          ??return?{
          ????hello:?'world',
          ??};
          }
          const?animal?=?new?Animal();??//?{?hello:?'world'?}

          在實(shí)例化構(gòu)造函數(shù)時(shí),返回非對(duì)象類型將不生效

          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)。而且無論您加多少個(gè) .call,效果也是一樣的。

          5

          實(shí)例后的對(duì)象也能再次實(shí)例嗎?

          function?People()?{}

          const?lili?=?new?People();????????????//?People?{}
          const?lucy?=?new?tom.constructor();???//?People?{}

          因?yàn)?lili原型鏈指向了 People 的原型,所以通過向上尋找特性,最終在 Peopel.prototype 上找到了構(gòu)造器即 People 自身

          6

          setTimeout 嵌套會(huì)發(fā)生什么奇怪的事情?

          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 層時(shí),間隔至少是 4ms 。

          7

          es6函數(shù)帶默認(rèn)參數(shù)時(shí)將生成聲明作用域

          var?x?=?10;

          function?fn(x?=?2,?y?=?function?()?{?return?x?+?1?})?{
          ??var?x?=?5;
          ??return?y();
          }

          fn();???//?3

          8

          函數(shù)表達(dá)式(非函數(shù)聲明)中的函數(shù)名不可覆蓋

          const?c?=?function?CC()?{
          ??CC?=?123;
          ??return?CC;
          };

          c();?//?Function

          當(dāng)然,如果設(shè)置 var CC = 123 ,加聲明關(guān)鍵詞是可以覆蓋的。

          9

          嚴(yán)格模式下,函數(shù)的 thisundefined 而不是 Window

          //?非嚴(yán)格
          function?fn1()?{
          ??return?this;
          }
          fn1();?//?Window

          //?嚴(yán)格
          function?fn2()?{
          ??'use?strict';
          ??return?this;
          }
          fn2();?//?undefined

          對(duì)于模塊化的經(jīng)過webpack打包的代碼,基本都是嚴(yán)格模式的代碼。

          10

          取整操作也可以用按位操作

          var?x?=?1.23?|?0;??//?1

          因?yàn)榘次徊僮髦恢С?2位的整型,所以小數(shù)點(diǎn)部分全部都被拋棄

          11

          indexOf() 不需要再比較數(shù)字

          const?arr?=?[1,?2,?3];

          //?存在,等效于?>?-1
          if?(~arr.indexOf(1))?{

          }

          //?不存在,等效于?===?-1
          !~arr.indexOf(1);

          按位操作效率高點(diǎn),代碼也簡(jiǎn)潔一些。也可以使用es6的 includes() 。但寫開源庫(kù)需要考慮兼容性的道友還是用 indexOf 比較好

          12

          getter/setter 也可以動(dòng)態(tài)設(shè)置嗎?

          class?Hello?{
          ??_name?=?'lucy';
          ?
          ??getName()?{
          ????return?this._name;
          ??}
          ??
          ??//?靜態(tài)的getter
          ??get?id()?{
          ????return?1;
          ??}
          }

          const?hel?=?new?Hello();

          hel.name;???????//?undefined
          hel.getName();??//?lucy

          //?動(dòng)態(tài)的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

          浮點(diǎn)操作不精確,老生常談了,不過可以接受誤差

          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

          正式代碼的原型繼承,不會(huì)直接實(shí)例父類,而是實(shí)例一個(gè)空函數(shù),避免重復(fù)聲明動(dòng)態(tài)屬性

          const?extends?=?(Child,?Super)?=>?{
          ??const?fn?=?function?()?{};
          ??
          ??fn.prototype?=?Super.prototype;
          ??Child.prototype?=?new?fn();
          ??Child.prototype.constructor?=?Child;
          };

          15

          es6居然可以重復(fù)解構(gòu)對(duì)象

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

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

          一行代碼同時(shí)獲取 aa.b 。 在a和b都要多次用到的情況下,普通人的邏輯就是先解構(gòu)出 a ,再在下一行解構(gòu)出 b 。

          16

          判斷代碼是否壓縮居然也這么秀

          function?CustomFn()?{}

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

          17

          對(duì)象 === 比較的是內(nèi)存地址,而 >= 將比較轉(zhuǎn)換后的值

          {}?===?{}?//?false

          //?隱式轉(zhuǎn)換?toString()
          {}?>=?{}??//?true

          18

          intanceof 的判斷方式是原型是否在當(dāng)前對(duì)象的原型鏈上面

          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原型是不允許被重新定義的,所以不會(huì)出現(xiàn)上述情況

          19

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

          這是原型鏈向上查找的最頂層,一個(gè) null

          20

          parseInt 太小的數(shù)字會(huì)產(chǎn)生 bug

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

          21

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

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

          22

          arguments 和形參是別名關(guān)系

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

          但是您可以用 use strict 嚴(yán)格模式來避免這一行為,這樣 arguments 就只是個(gè)副本了。

          23

          void 是個(gè)固執(zhí)的老頭

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

          跟誰都不沾親~~

          24

          try/catch/finally 也有特定的執(zhí)行順序

          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; 關(guān)鍵詞,那么 xxyyzz 會(huì)先執(zhí)行并把值放在臨時(shí)變量里,接著去執(zhí)行 finally 代碼塊的內(nèi)容后再返回該臨時(shí)變量。 如果 finally 中也有 return aabbcc ,那么會(huì)立即返回新的數(shù)據(jù) aabbcc 。

          25

          是否存在這樣的變量 x ,使得它等于多個(gè)數(shù)字?

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

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

          通過隱式轉(zhuǎn)換,這樣不是什么難的事情。

          26

          clearTimeoutclearInterval 可以互換~~~~使用嗎

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

          clearInterval(timeout);
          clearTimeout(interval);

          答案是:YES 。大部分瀏覽器都支持互相清理定時(shí)器,但是建議使用對(duì)應(yīng)的清理函數(shù)。

          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

          主線任務(wù):2,4?

          微任務(wù):3,5?
          宏任務(wù):1

          28

          nullobject 類型,但又不是繼承于 Object ,它更像一個(gè)歷史遺留的 bug 。鑒于太多人在用這個(gè)特性,修復(fù)它反而會(huì)導(dǎo)致成千上萬的程序出錯(cuò)。

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

          腦袋空了,想到再加。。。

          瀏覽 63
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩成人电影中文字幕 | 婷婷丁香六月天 | 逼逼国产 | 亚洲黄色在线电影 | 亚洲免费观看高清视频 |