前端經常使用代碼片斷(三)

最後更新於2019年1月13日

前端經常使用代碼片斷(一) 點這裏
前端經常使用代碼片斷(二) 點這裏
前端經常使用代碼片斷(三) 點這裏
前端經常使用代碼片斷(四) 點這裏
前端經常使用代碼片斷(五) 點這裏
前端經常使用代碼片斷(六) 點這裏javascript


1.打亂數組中元素順序(相似音樂隨機播放)

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min)
}

export function shuffle(arr) {
  let _arr = arr.slice()
  for (let i = 0; i < _arr.length; i++) {
    let j = getRandomInt(0, i)
    let t = _arr[i]
    _arr[i] = _arr[j]
    _arr[j] = t
  }
  return _arr
}

擴展:html

1.取[10,100) 的隨機整數方法

Math.floor(Math.random()*90+10);

2.取[10,100] 的隨機整數方法

function randomBy(under, over){ 
   switch(arguments.length){ 
     case 1: return parseInt(Math.random()*under+1); 
     case 2: return parseInt(Math.random()*(over-under+1) + under); 
     default: return 0; 
   } 
} 

randomBy(10, 100);
//隨機返回一個範圍的數字
    randomNumber(n1, n2) {
        //randomNumber(5,10)
        //返回5-10的隨機整數,包括5,10
        if (arguments.length === 2) {
            return Math.round(n1 + Math.random() * (n2 - n1));
        }
        //randomNumber(10)
        //返回0-10的隨機整數,包括0,10
        else if (arguments.length === 1) {
            return Math.round(Math.random() * n1)
        }
        //randomNumber()
        //返回0-255的隨機整數,包括0,255
        else {
            return Math.round(Math.random() * 255)
        }
    }

3.利用sort()

咱們先產生個數組前端

var arr=[];
for(var i=0;i<10;i++){
    arr.push(i)
}
console.log(arr)    // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

咱們之前的正常排序是這樣的:java

arr.sort(function(a,b){
    return b-a
});

接下來咱們來打亂它:node

arr.sort(()=>{
    return Math.random() - 0.5
})                 // [1, 0, 2, 3, 4, 6, 8, 5, 7, 9]

第二種打亂方法:jquery

arr.sort((a,b)=>{
    return a > Math.random()*10;
})                // [1, 2, 0, 6, 4, 3, 8, 9, 7, 5]

解析:git

先說正常的排序:
a,b表示數組中的任意兩個元素,若return > 0 ,b前a後;若reutrn < 0 則a前b後;當a=b時,則存在瀏覽器兼容 ;
a-b輸出從小到大排序,b-a輸出從大到小排序。
而後再說咱們打亂的方法:
建立數組不用說,接下來就是用js的sort方法 來實現,Math.random()實現一個隨機0-1之間的小數 而後再減去0.5,這時就會根據return比較後獲得的值排序,因此說就會生成不是正常從大到小或者從小到大的排序。

2.函數節流(throttle)和 函數去抖(debounce)

函數節流函數去抖 都是爲了項目優化而出現的,官方是沒有具體定義的,他們的出現主要是爲了解決一些短期內連續執行的事件帶來性能上的不佳和內存的消耗巨大等問題;像這類事件通常像 scroll keyup mousemove resize等等,短期內不斷的觸發,在性能上消耗是很是大的,尤爲是一些改變DOM結構的操做;es6

節流[throttle]與防抖[debounce]很是類似,都是讓上述這類事件裏定義的代碼 從不斷的執行 更改爲爲 規定的時間內執行多少次;github

函數節流(throttle) 應用場景

函數節流(throttle),例如實現一個拖拽功能,須要一路監聽 mousemove 事件,在回調中獲取元素當前位置,而後重置 dom 的位置(樣式改變)。若是咱們不加以控制,每移動必定像素而觸發的回調數量是會很是驚人的,回調中又伴隨着 DOM 操做,繼而引起瀏覽器的重排與重繪,性能差的瀏覽器可能就會直接假死,這樣的用戶體驗是很是糟糕的。咱們須要作的是下降觸發回調的頻率,好比讓它 500ms 觸發一次,或者 1000ms,這個閾值不能太大,太大了拖拽就會失真,也不能過小,過小了低版本瀏覽器可能就會假死,這樣的解決方案就是函數節流。函數節流的核心是,讓一個函數不要執行得太頻繁,減小一些過快的調用來節流web

函數節流有哪些應用場景?哪些時候咱們須要間隔必定時間觸發回調來控制函數調用頻率?

  • DOM 元素的拖拽功能實現(mousemove)
  • 射擊遊戲的 mousedown/keydown 事件(單位時間只能發射一顆子彈)
  • 計算鼠標移動的距離(mousemove)
  • Canvas 模擬畫板功能(mousemove)
  • 搜索聯想(keyup)
  • 監聽滾動事件判斷是否到頁面底部自動加載更多:給 scroll 加了 debounce 後,只有用戶中止滾動後,纔會判斷是否到了頁面底部;若是是 throttle 的話,只要頁面滾動就會間隔一段時間判斷一次

節流通俗來解釋就好比咱們水龍頭放水,閥門一打開,水嘩嘩的往下流,這個秉着勤儉節約的優良傳統美德,咱們要把水龍頭關小點,最好是如咱們心意按照必定規律在某個時間間隔內一滴一滴的往下滴,這,,,好吧這就是咱們節流的概念;換成函數來講,使用setTimeout方法,給定兩個時間,後面的時間減去前面的時間,到達咱們給定的時間就去觸發一次這個事件,這麼說太籠統的,咱們看下面的函數,這裏咱們以【scroll】爲例;

/** 樣式我就順便寫了 **/
<style>
    *{padding:0;margin:0;}
    .scroll-box{
        width : 100%;
        height : 500px;
        background:blue;
        overflow : auto;
    }    
    .scroll-item{
        height:1000px;
        width:100%;
    }
</style>

------------------------

/** 先給定DOM結構;**/
<div class="scroll-box">
    <div class="scroll-item"></div>
</div>

------------------------

/**主要看js,爲了簡單我用JQ去寫了**/
<script>
    $(document).ready(function(){
        var scrollBox = $('.scroll-box');
        //調用throttle函數,傳入相應的方法和規定的時間;
        var thro = throttle(throFun,300);
        //觸發事件;
        scrollBox.on('scroll' , function(){
            //調用執行函數;
            thro();
        })

        // 封裝函數;    
        function throttle(method,time){
            var timer = null;
            var startTime = new Date();
            return function(){
                var context = this;
                var endTime = new Date();
                var resTime = endTime - startTime;
                //判斷大於等於咱們給的時間採起執行函數;
                if(resTime >= time){
                    method.call(context);
                    //執行完函數以後重置初始時間,等於最後一次觸發的時間
                    startTime = endTime;
                }
            }
        }
        function throFun(){
            console.log('success');
        }
    })
</script>

export function throttle(delay, action){
  let last = return function(){
    let curr = +new Date()
    if (curr - last > delay){
      action.apply(this, arguments)
      last = curr 
    }
  }
}

函數去抖(debounce) 應用場景

寫代碼以前,咱們先清楚一下防抖的概念,不知道你們有沒有作過電腦端兩邊懸浮廣告窗口的這麼一個東西,當咱們拖動滾動條的時候,兩邊的廣告窗口會由於滾動條的拖動,而不斷的嘗試着去居於中間,而後你就會看到這兩個窗口,不停的抖啊抖;

通常這種就叫抖動了,咱們要作的就是防止這種抖動,稱爲防抖[debounce ];

那這裏防抖思想就是當咱們拖動完成以後,兩邊的窗口位置再從新去計算,這樣,就會顯得很平滑,看着很舒服了,最主要的操做DOM結構的次數就大大減小了;

優化了頁面性能,下降了內存消耗,否則你像IE這種比較老點版本的瀏覽器,說不定就直接給你蹦了

用書面一點的說法就是,在某個事件沒有結束以前,函數不會執行,當結束以後,咱們給定延時時間,然他在給定的延時時間以後再去執行這個函數,這就是防抖函數;

來看代碼:

//將上面案例的throttle函數替換爲debounce函數;
function debounce(method,time){
    var timer = null ;
    return function(){
        var context = this;
        //在函數執行的時候先清除timer定時器;
        clearTimeout(timer);
        timer = setTimeout(function(){
            method.call(context);
        },time);
    }
}

思路就是在函數執行以前,咱們先清除定時器,若是函數一直執行,就會不斷的去清除定時器中的方法,知道咱們操做結束以後,函數纔會執行;

export function debounce(func, delay) {
  let timer
  return function(...args) {
    if (timer) {
      clearTimeout(timer)
    }

    timer = setTimeout(() => {
      func.apply(this, args)
    }, delay)
  }
}

用途

  • 當咱們作keyup像後臺請求檢驗的時候,可使用防抖函數,否則咱們每按一次鍵盤就請求一次,請求太頻繁,這樣當咱們結束按鍵盤的時候再去請求,請求少不少了,性能天然不用說;
  • resize 窗口大小調整的時候,咱們能夠採用防抖技術也可使用節流;
  • mousemove 鼠標移動事件咱們既能夠採用防抖也可使用節流;
  • scroll 滾動條觸發的事件,固然既能夠採用防抖也能夠採用節流;
  • 連續高頻發的事件均可以採用這兩種方式去解決,優化頁面性能;

具體的採用哪種更較爲合適,主要仍是看你的業務需求

區分

節流說白了就是每ms執行一次函數,防抖就是 最後一次觸發後ms後執行一次回調函數。
節流就是擰緊水龍頭,讓水滴一滴一滴流,而去抖則是按壓一個彈簧,不鬆手則彈簧不會觸發

函數節流和去抖都是限制基於DOM事件執行的javascript數量的方法,都是爲了提升JS性能,可是二者是有區別的。

推薦閱讀
函數節流和去抖之間的區別

本小節引用
avaScript 函數節流...
JavaScript 高級系列...

3.img寬高同樣,border-radius: 50%,爲何不是正圓

這個是網上一個網友提的問題,本身不曾遇到也爲實驗,先保存在這
源代碼:

<div>
    <img style="width: 60px;height:60px;border-radius: 50%" src="~@/asset/person.jpg">
</div>

緣由:
圖片的比例不是1:1(圖片縱橫比不爲1)

解決方法:(待驗證)

<img width="60" height="60" style="border-radius: 50%" src="~@/asset/person.jpg">

border-radius:100%

4.如何優雅的實現金錢格式化:1234567890 --> 1,234,567,890

用正則魔法實現:

var test1 = '1234567890'
var format = test1.replace(/\B(?=(\d{3})+(?!\d))/g, ',')

console.log(format) // 1,234,567,890

非正則的優雅實現:

function formatCash(str) {
       return str.split('').reverse().reduce((prev, next, index) => {
            return ((index % 3) ? next : (next + ',')) + prev
       })
}
console.log(formatCash('1234567890')) // 1,234,567,890

5.如何最佳的讓兩個整數交換數值

常規辦法:

var a=1,b=2;
a += b;
b = a - b;
a -= b;

缺點也很明顯,整型數據溢出,對於32位字符最大表示數字是2147483647,若是是2147483645和2147483646交換就失敗了。
黑科技辦法:

a ^= b;
b ^= a;
a ^= b;

es6:

[b,a] = [a,b]

6.實現標準JSON的深拷貝

var a = {
    a: 1,
    b: { c: 1, d: 2 }
}
var b=JSON.parse(JSON.stringify(a))

不考慮IE的狀況下,標準JSON格式的對象蠻實用,不過對於undefined和function的會忽略掉。

7.在str前添加一個➕號,+str會強制轉Number

不用Number、parseInt和parseFloat和方法把"88"字符串轉換成數字

var str="88";
console.log(+str)   // 88
//或者
console.log(str - 0)   // 88
//可是若是是混合類型的字符串,則會轉爲NaN
var b="1606e";
console.log(+b)     // NaN

8.數組去重

方法1:最短的代碼實現es6
[...new Set([1, "1", 2, 1, 1, 3])]

function uniqueArray(arr){
    return Array.from(new Set(arr));
}

方法2:使用filter + indexOf

以下代碼所示:

removeRepeatArray(arr) {
    return arr.filter(function (item, index, self) {
       return self.indexOf(item) === index;
    });
}

方法3:使用splice

以下代碼所示:

function uniqueArray(arr){
    for(var i = 0; i < arr.length - 1; i++){
        for(var j = i + 1; j < arr.length; j++){
            if(arr[j] === arr[i]){
                arr.splice(j--, 1);
            }
        }
    }
    return arr;
}

方法4:只用Array
以下代碼所示:

function uniqueArray(arr){
    var retArray = [];
    for(var i = 0; i < arr.length; i++){
        if(retArray.indexOf(arr[i]) < 0){
            retArray.push(arr[i]);
        }
    }
    return retArray;
}

方法5:Object.keys(對象)

let a = ['1', '2', '3', 1,NaN,NaN,undefined,undefined,null,null, 'a', 'b', 'b'];
    const unique = arr => {
        var obj = {}
        arr.forEach(value => {
            obj[value] = 0;//這步新添加一個屬性,並賦值,若是不賦值的話,屬性會添加不上去
        })
        return Object.keys(obj);//`Object.keys(對象)`返回這個對象可枚舉屬性組成的數組,這個數組就是去重後的數組
    }
    console.log(unique(a));//["1", "2", "3", "NaN", "undefined", "null", "a", "b"]

注意:
這個方法會將 number,NaN,undefined,null,變爲字符串形式,由於對象的屬性名就是一個字符串

9.用最短的代碼實現一個長度爲m(6)且值都n(8)的數組

Array(6).fill(8)

10.取出一個數組中的最大值和最小值

var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; 

var maxInNumbers = Math.max.apply(Math, numbers); // 或 Math.max(...arr)
 
var minInNumbers = Math.min.apply(Math, numbers); // 或 Math.min(...arr)

11.將argruments對象轉換成數組

var argArray = Array.prototype.slice.call(arguments);

或者ES6:

var argArray = Array.from(arguments)

12.短路表達式

條件判斷

var a = b && 1
// 至關於
if (b) {
    a = 1
} else {
    a = b
}
var a = b || 1
// 至關於
if (b) {
    a = b
} else {
    a = 1
}

13.RGB to Hex

function toHEX(rgb){
    return ((1<<24) + (rgb.r<<16) + (rgb.g<<8) + rgb.b).toString(16).substr(1);
}

14.JSON.stringify()妙用

1 語法
JSON.stringify(value[, replacer[, space]])
通常用法:

var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user);
"{"name":"andy","isDead":false,"age":11,"addr":"shanghai"}"

2 擴展用法
2.1 replacer
replacer能夠是函數或者是數組。

功能1: 改變屬性值
將isDead屬性的值翻譯成0或1,0對應false,1對應true

var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, function(key, value){
    if(key === 'isDead'){
        return value === true ? 1 : 0;
    }
    return value;
});
//"{"name":"andy","isDead":0,"age":11,"addr":"shanghai"}"

功能2:刪除某個屬性
將isDead屬性刪除,若是replacer的返回值是undefined,那麼該屬性會被刪除。

var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, function(key, value){
    if(key === 'isDead'){
        return undefined;
    }
    return value;
});
//"{"name":"andy","age":11,"addr":"shanghai"}"

功能3: 經過數組過濾某些屬性
只須要name屬性和addr屬性,其餘不要。

var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, ['name', 'addr']);
//"{"name":"andy","addr":"shanghai"}"

2.2 space
space能夠是數字或者是字符串, 若是是數字則表示屬性名前加上空格符號的數量,若是是字符串,則直接在屬性名前加上該字符串。

功能1: 給輸出屬性前加上n個空格

var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, null, 4);
"{
    "name": "andy",
    "isDead": false,
    "age": 11,
    "addr": "shanghai"
}"

功能2: tab格式化輸出

var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
JSON.stringify(user, null, '\t');
"{
    "name": "andy",
    "isDead": false,
    "age": 11,
    "addr": "shanghai"
}"

功能3: 搞笑

JSON.stringify(user, null, 'good');
"{
good"name": "andy",
good"isDead": false,
good"age": 11,
good"addr": "shanghai"
}"

2.3 深拷貝

var user = {name: 'andy', isDead: false, age: 11, addr: 'shanghai'};
var temp = JSON.stringify(user);
var user2 = JSON.parse(temp);

3 其餘
JSON.parse() 其實也是支持第二個參數的。功能相似於JSON.stringify的第二個參數的功能。


15.獲取jquery版本號

console.log('$',$.fn.jquery)
//$ 3.2.1

16.img異步加載圖片

在開發中,咱們常常有異步加載圖片的請求,而後在圖片加載成功後作一些操做,通常咱們經過onload方法來實現.網上有兩種寫法,你們能夠先看一下(注:logo.jpg是張本地圖片):

例子1:

var img = new Image();
 img.src = "logo.jpg";
 img.onload = function () {
    alert("image is loaded");
 };
 document.body.appendChild(img);

例子2:

var img = new Image();
 img.onload = function () {
    alert("image is loaded");
 };
 img.src = "logo.jpg";
 document.body.appendChild(img);

發現什麼了沒有?上面兩個例子最大的差異就在於onload和src賦值的前後順序.那麼onload和src賦值的前後順序會在實際中產生什麼差異呢?

產生這個問題的緣由很簡單,就是由於logo.jpg是本地圖片,致使瀏覽器加載起來很是快,幾乎在給img賦值src的時候,圖片就已經加載完成,同時觸發了onload事件,代碼中爲onload賦值的語句就至關於在onload事件發生後,這時候已經晚了.

將src寫到了onload的前面,會致使onload來不及賦值就被執行了,因此正確的寫法應該是第2個例子.既在給圖片分配地址前,先綁定好它的onload事件,這樣就不用擔憂錯過期機的問題了.

正確的例子:

var img = new Image();
// 若是文檔裝入完成後加載用window load
//window.addEventListener("load" , function(){
//    document.body.appendChild(img);
//} , false);
        
// 若是圖片加載完畢用 img load
img.addEventListener('load', function(){
  document.body.appendChild(img);
} , false);

img.src = 'test.png';

17.幾個經常使用的console用法

1.console.log(): 進行標準輸出流的輸出(stdout)

console.group('mounted 掛載結束狀態===============》');
console.log("%c%s", "color:green","data   : " + this.$data)

2.console.error(): 進行標準錯誤流的輸出用法與console.log()同樣.

3.console.dir(): 查看一個對象的內容,並把對象信息輸出到控制檯.

// a.js
var person = {
  age: 38,
  name: 'kobe',
  job: function(){
    return 'player'
  }
};
console.log(person);
// node a.js
{ age: 38, name: 'kobe', job: [Function: job] }

4.console.time()與console.timeEnd() : 能夠用來統計一段代碼的執行時間

// a.js
console.time('loop');
for(var i =0;i < 10000;i++){
  ;
}
console.timeEnd('loop');
// node a.js
loop: 0.283ms

好玩的console.log()

console.log("%c3"," text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:6em;line-height:60px;")

console.log("%c2"," text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:4em;line-height:60px;")

console.log("%c1"," text-shadow: 0 1px 0 #ccc,0 2px 0 #c9c9c9,0 3px 0 #bbb,0 4px 0 #b9b9b9,0 5px 0 #aaa,0 6px 1px rgba(0,0,0,.1),0 0 5px rgba(0,0,0,.1),0 1px 3px rgba(0,0,0,.3),0 3px 5px rgba(0,0,0,.2),0 5px 10px rgba(0,0,0,.25),0 10px 10px rgba(0,0,0,.2),0 20px 20px rgba(0,0,0,.15);font-size:2em;line-height:60px;")

console.log('%c南京熱仍是東京熱.', 'color: #fff; background: #f40; font-size: 24px;border-radius:0 15px 15px 0;padding:10px;');

console.log("%c                                           ","background-image:-webkit-gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );color:transparent;-webkit-background-clip: text;font-size:5em;width:1px;height:40px;padding:2px;")

console.log("%c  熱 熱 熱", "color:red;font-size:30px;font-weight:bolder;padding:50px 420px;line-height:10px;background:url('http://img.zcool.cn/community/0127c0577e00620000012e7e12da0e.gif') repeat-x;background-size:contain;");

18. !!強制轉布爾值boolean

根據當前須要判斷的值是真值仍是假值來判斷,真值返回true,假肢返回false,那麼這樣的話,除了假值,剩下的也都是真值了。

假值有:0 、 「」 、 null 、 undefined 、 false 、NaN

除了這 6 個外,其它均爲「真」 ,包括對象、數組、正則、函數等。
注意: '0'、'null'、'false'、{}、[]也都是真值 。
那麼下面咱們來看看!!是如何轉布爾值的。
例如:
首先咱們聲明3個變量,x爲null,y爲空字符串,str爲字符串,下面看看他們添加了"!!"後會有什麼結果。
var x=null;
var y="";
var str="abcd";

console.log(!!x)      // false;
console.log(!!y)      // false;
console.log(!!str)    // true;
如上所說,假值返回false,真值返回true。

19. 不可靠的undefined 可靠的void 0

在JavaScript中,假設咱們想判斷一個是不是 undefined,那麼咱們一般會這樣寫:

if(a === undefined){
 dosomething.....
}

由於在javascript中,undefined是不可靠的
例如:
當undefined被放在在function函數內,咱們把它當成一個局部變量,它是能夠賦上值的,下面咱們來試試。

function foo2(){
    var undefined=1;
    console.log(undefined)
}
foo2();     // 1;

可是當在函數內定義一個全局變量,並不能給賦上值

var undefined;
function foo2(){
    undefined=1;
    console.log(undefined)
}
foo2()    // undefined

那麼咱們試試用void 0或者 void (0)來代替:
先聲明一個變量a,賦值爲undefined,接下來咱們用void 0來判斷一下。

var a=undefined;

//用void 0來判斷一下
if(a===void 0){
    console.log('true')
}       // true

//再用void (0)來判斷一下
if(a===void (0)){
    console.log('true')
}       // true
//最後咱們打印一下這兩個的返回值
console.log(void 0,void (0))    // undefined undefined

咱們如今能夠經過void 0 運算來得到 undefined;那在之後須要判斷值爲undefined的時候,能夠直接用void 0或者void (0),並且這兩個值的直接返回值就是undefined,因此說很是可靠哦!

20.用typeof來判斷對象的潛在陷阱

問:使用 typeof bar === "object" 來肯定 bar 是不是對象的潛在陷阱是什麼?如何避免這個陷阱?

儘管 typeof bar === "object" 是檢查 bar 是否對象的可靠方法,使人驚訝的是在JavaScript中 null 也被認爲是對象!

所以,令大多數開發人員驚訝的是,下面的代碼將輸出 true 控制檯:

var bar = null;
console.log(typeof bar === "object");  
// logs true!

只要清楚這一點,同時檢查 bar 是否爲 null,就能夠很容易地避免問題:

console.log(
  (bar !== null) && (typeof bar === "object")
);  
// logs false

要答全問題,還有其餘兩件事情值得注意:

首先,上述解決方案將返回 false,當 bar 是一個函數的時候。在大多數狀況下,這是指望行爲,但當你也想對函數返回 true 的話,你能夠修改上面的解決方案爲:

console.log(
  (bar !== null) && ((typeof bar === "object") || (typeof bar === "function"))
);

第二,上述解決方案將返回 true,當 bar 是一個數組(例如,當 var bar = [];)的時候。

在大多數狀況下,這是指望行爲,由於數組是真正的對象,但當你也想對數組返回 false 時,你能夠修改上面的解決方案爲:

console.log(
  (bar !== null)&& (typeof bar === "object") && (toString.call(bar) !== "[object Array]")
);

或者,若是你使用jQuery的話:

console.log(
  (bar !== null)&& (typeof bar === "object") && (! $.isArray(bar))
);

或者 數組和函數返回false,但對於對象則爲true:

console.log((bar !== null) && (bar.constructor === Object));

參考:
1.這些JavaScript編程黑科技...
2.圖片的異步加載與onload函數
3.原生js的經常使用方法整理
4.ec-do-2.0.0.js

相關文章
相關標籤/搜索