1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        JavaScript 里的奇葩知識

        共 5947字,需瀏覽 12分鐘

         ·

        2020-12-19 13:01



        授權轉載自:原罪?

        https://segmentfault.com/a/1190000023941089

        久經沙場的前輩們,寫了無數代碼,踩了無數的坑。但有些坑,可能一輩子也踩不到摸不著,因為根本不會發(fā)生在業(yè)務代碼里~~

        1

        Function.prototype 竟然是個函數類型。而自定義函數的原型卻是對象類型。

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

        function?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了新的數據

        //?不返回
        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?tom.constructor();???//?People?{}

        因為 lili原型鏈指向了 People 的原型,所以通過向上尋找特性,最終在 Peopel.prototype 上找到了構造器即 People 自身

        6

        setTimeout 嵌套會發(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 層時,間隔至少是 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

        嚴格模式下,函數的 thisundefined 而不是 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 也可以動態(tài)設置嗎?

        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

        //?動態(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

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

        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

        正式代碼的原型繼承,不會直接實例父類,而是實例一個空函數,避免重復聲明動態(tài)屬性

        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;

        一行代碼同時獲取 aa.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)?{
        ??console.log(a,?b);?//?2,?3
        ??
        ??arguments[0]?=?100;
        ??arguments[1]?=?200;
        ??
        ??console.log(a,?b);?//?100,?200
        }
        test(2,?3);

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

        23

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

        25

        是否存在這樣的變量 x ,使得它等于多個數字?

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

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

        通過隱式轉換,這樣不是什么難的事情。

        26

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

        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

        nullobject 類型,但又不是繼承于 Object ,它更像一個歷史遺留的 bug 。鑒于太多人在用這個特性,修復它反而會導致成千上萬的程序出錯。

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

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

        瀏覽 63
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            99视频内射三四 | 黄色床上搞鸡网站 | 好爽还要再深点好硬 | 黄频网站在线观看 | 在线免费观看成人视屏 | h狠狠地操你h各种姿势男男视频 | 精品国产97 .. | 一进一出下面喷白浆九瑶视频 | 国产精品不卡 | 男人操女人的逼软件 |