天天看點

js與jquery常用方法總結

原文:http://www.tuicool.com/articles/2QZ3QvV

昨天被問數組方法的時候,問到sort()方法是否會改變原來的數組。本來我猜是不會,也是這麼說,馬上我又覺得,知識這種東西,不确定的時候直接說不确定或不知道就好,隻是憑借着不确定的猜測或者是記憶,害人害己,于是我又回答不知道。結果果然。。。我記錯了0.0 還是自己總結測試一下比較靠譜,印象也比較深刻。歡迎大家提出相關意見或建議,提前謝謝哈~

一.原生js方法

1.周遊數組 in(同時也是對象周遊屬性的方法)

var a = [1, 2, 3];
for (x in a) {
    console.log(x);
}      

2.合并數組 concat

var a = [1, 2, 3],
    b = [4, 5, 6],
    c;
c = b.concat(a);     //将a加在b上,傳回新數組,a和b并沒有變。參數數量不限
console.log(b);
console.log(c);      

3.合并數組的值為字元串 join

var a = [1, 2, 3],
    b = a.join('*'); //預設為之間加上 ,          
console.log(a);      //a并沒有變
console.log(b);      

參數為分隔符,預設為" , "分隔,當參數為' '時表示直接連接配接,常用于js中拼接html,如自定義彈窗,js生成form表單。

4.數組排序 sort

var a = [6, 2, 3, 'a', 'x', 20],
    b = a.sort();          //ASC表順序,先看首位,是以20排在3前面
console.log(a);            //a變化了
console.log(b);
a.push('k');
console.log(b);            //a和b指向同一個對象,b相當于a的别名
           

可以在參數裡寫排序規則函數, 如全是數字從小到大排序(注意傳回值正負)

var a = [3, 2, 6, 20],
    b = a.sort(function(x, y) {
        return x - y;
    });
console.log(b);
           

當不全是數字的時候,會産生奇葩錯誤(NaN),見下圖

js與jquery常用方法總結
js與jquery常用方法總結

由此可知,注意運算符的正确用法還是很重要的。對于NaN,能少操作就少操作,畢竟是唯一一個js中不等于任何值的類型(Not a Number),包括它本身(可以用來判斷一個變量是不是NaN,未初始化的變量是無類型的)。

5.數組的模拟棧(FILO) 和隊列(FIFO) 方法 (均改變原來數組)

var a = [6, 2, 3, 'a', 'x', 20],
  b = a.push('ab'),	//末尾添加元素,并傳回新長度
  c = a.pop(),		 //删除并傳回數組的最後一個元素
  d = a.unshift('xy'), //開頭添加元素,并傳回新長度
  e = a.shift();	   //删除并傳回數組的第一個元素
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);
      

可見這類方法添加元素則傳回添加後長度, 删除元素則傳回被删的那個可憐家夥(同splice)。

6.數組反序 reverse

var a = [6, 2, 3, 'a', 'x', 20],
    b = a.reverse();       //傳回a的引用
console.log(a);
console.log(b);      

7.取數組中需要的部分 slice

var a = [6, 2, 3, 'a', 'x', 20],
    b = a.slice(0, 2);    //下标從0取到2(不包括2),沒有第二個參數則預設到末尾。第一個參數為負表示從末尾開始數。第一個參數小于第二個參數則為空。
console.log(a);
console.log(b);           //b是a一部分的副本,a本身不變
           

8.修改數組 splice (既然是修改數組,肯定數組本身會 變 的啦)

var a = [1, 2, 3, 4],
    b = a.splice(0, 2, 6);
console.log(a);          
console.log(b);          //b為被删掉的數組部分      

a.splice(index, num, newItem1, newItem2...):index為開始選擇的元素下标,num為接下來要删除元素的個數,newItem為接下來(在删完的地方)要添加的新元素(非必須)。這個方法用途最多,如

删除指定下标(2,也就是第三個)元素,此時不設定需要添加的newItem,而num設為1

var a = [1, 2, 3, 4],
    b = a.splice(2, 1);
console.log(a);
console.log(b);       

在任意位置添加任意多個元素(如在下标2後添加兩個元素'7','8'),此時num設為0

var a = [1, 2, 3, 4],
    b = a.splice(2, 0, 7,8);
console.log(a);
console.log(b);   //沒有删除,b傳回[]      

根據元素值删除元素(結合jquery)

var a=[1,2,3,4];
a.splice($.inArray(2,a),1);
console.log(a);      

plus:數組也是特殊的對象(但是擁有自己的方法,一般用下标通路),是以同樣也有對象的通用方法toString和valueOf

var a = [1, 2, [3,2], 4],
    b = a.toString(); // 轉化為字元串(不管有多少層)
console.log(a);       //a本身不變
console.log(b);      
var a = [1, 2, 4],
    b = a.valueOf();  // 傳回原始值(其實還是它本身。。。)
console.log(a);       //a本身不變
console.log(b);      

小結:綜上所述,js數組的原生方法裡面

修改自身的有: splice, pop, push, shift, unshift, sort, reverse

不修改自己身的: slice, concat, join

二.Jquery常用js方法

1.周遊

可以對所有的元素進行操作。如果想要滿足條件退出,用return false( 絕大部分jquery方法都可以這麼退出)。

$.each(arr, callback(key, val));      //可以鍊式調用, 傳回arr,為本身

var a = [1, 2, 3, 4];
$.each(a, function(key, val) {     //以jQuery對象的方法調用,相容性好;也可以用$(a)将a轉化為jquery對象,然後以$(a).each(function(){})的形式調用,下面的方法同
    console.log(a[key] + '下标為' + key + '值為' + val);
});      

// Execute a callback for every element in the matched set.

// (You can seed the arguments with an array of args, but this is

// only used internally

.

each: function( obj, callback, args ) {
  var value,
    i = 0,
    length = obj.length,
    isArray = isArraylike( obj );
  if ( args ) {
    if ( isArray ) {
      for ( ; i < length; i++ ) {
        value = callback.apply( obj[ i ], args );   //第三個參數用于擴充obj元素的方法,一般不用
        if ( value === false ) {
          break;
        }
      }
    } else {
      for ( i in obj ) {
        value = callback.apply( obj[ i ], args );
        if ( value === false ) {
          break;
        }
      }
    }
  // A special, fast, case for the most common use of each
  } else {
    if ( isArray ) {
      for ( ; i < length; i++ ) {
        value = callback.call( obj[ i ], i, obj[ i ] );
        if ( value === false ) {
          break;
        }
      }
    } else {
      for ( i in obj ) {
        value = callback.call( obj[ i ], i, obj[ i ] );
        if ( value === false ) {
          break;
        }
      }
    }
  }
  return obj;
}
      

2. 篩選

$.grep(arr, callback, invert)

invert為false表示對callback的篩選取反。 預設為true。

var a = [1, 2, 3, 4];
$.grep(a, function(val, key) {  //不能鍊式調用,傳回[],是以可以加上return實作鍊式,傳回滿足條件的副本
  if (a[key] > 2) {
    console.log(key);
  }
  return val;
});      

常用做擷取兩個數組中相同(或不相同)的部分

var a= [1, 2, 3, 4],
    b=[1,3,5,7];
$.grep(a,function(val,key){
    if(b.indexOf(val)>=0){
        return val;
    }
},false);
           
//jquery源碼
grep: function( elems, callback, invert ) {
    var callbackInverse,
      matches = [],
      i = 0,
      length = elems.length,
      callbackExpect = !invert;
    // Go through the array, only saving the items
    // that pass the validator function
    for ( ; i < length; i++ ) {
      callbackInverse = !callback( elems[ i ], i );   //如果callback沒有設定return,那麼傳回undefined(!undefined還是undefined)
      if ( callbackInverse !== callbackExpect ) {
        matches.push( elems[ i ] );		  //隻添加滿足條件的,内部實作為push方法
      }
    }
    return matches;
  }
           

3.轉換

$.map(arr,callback(key,val))

var a = [1, 2, 3, 4];
$.map(a, function(val, key) { //不能鍊式調用,傳回[],同grep加上return即可放回副本
    if (a[key] > 2) {
        a[key]=val+1;
    }
    return val;              //可以鍊式調用,傳回處理後的數組(也可用于篩選)
});
           
// arg is for internal usage only
map: function( elems, callback, arg ) {
  var value,
    i = 0,
    length = elems.length,
    isArray = isArraylike( elems ),
    ret = [];
  // Go through the array, translating each of the items to their new values
  if ( isArray ) {
    for ( ; i < length; i++ ) {
      value = callback( elems[ i ], i, arg );
      if ( value != null ) {
        ret.push( value );
      }
    }
  // Go through every key on the object,
  } else {
    for ( i in elems ) {
      value = callback( elems[ i ], i, arg );   //如果callback沒有傳回值,那麼value就是undefined
      if ( value != null ) {
        ret.push( value );
      }
    }
  }
  // Flatten any nested arrays
  return concat.apply( [], ret );				   //如果callback沒有傳回值,那麼value就是[]
      
}      

背景标白的區域為與each方法不同的地方,可以簡單的了解為傳回對象是否是副本(map是副本),另外map是為數組或類數組對象量身定做的,而each可以應用于全部對象。

4.合并

$.merge(arr1,arr2)  arr1後面加上arr2後傳回arr1

var a=[1,2,3],
    b=[4,5,6];
$.merge(a,b);             //可以有多個參數(居然不報錯!),但是第三個及以後的沒用(test in FF and Chrome)
           
//jquery源碼
merge: function( first, second ) {
  var len = +second.length, 
      j = 0,
      i = first.length;
  while ( j < len ) {
      first[ i++ ] = second[ j++ ];
  }
  // Support: IE<9
  // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
  if ( len !== len ) {
      while ( second[j] !== undefined ) {
    first[ i++ ] = second[ j++ ];
      }
  }
  first.length = i;
  return first;
    }
           

源碼的第二行有個+,最開始我以為是顯式聲明非負值,後來看到了arraylike,于是測試了極端情況如下:

var ax;
ax.length        //報錯,type error
+ax.length       //報錯,type error

var ab={};       //空對象作為類空數組對象
ab.length        //undefined
+ab.length       //NaN

var ab=[];
ab.length        //0
+ab.length       //0

var ab=null;
ab.length     //報錯,type error
+ab.length       //報錯,type error      

忽然覺得然并卵。。。好吧,也許是我計較太多。如果有誰看到有關的解釋,麻煩留下言,謝謝~

5.過濾相同元素

$.unique(arr)//過濾Jquery對象數組中重複的元素(内部實作為===)(不同版本不一樣,不要用)

var a = [ 1 , 1 , 2 , 3 , 7 , 4 , 5 , 5 , 6 , 6 ];
$.unique(a)      

jquery1.11.0運作結果

js與jquery常用方法總結

jquery1.8.3運作結果

js與jquery常用方法總結

好神奇啊,有木有!看一下源碼保險~

//jquery1.11.0
jQuery.unique = Sizzle.uniqueSort;
Sizzle.uniqueSort = function( results ) {
  var elem,
    duplicates = [],
    j = 0,
      i = 0;
  // Unless we *know* we can detect duplicates, assume their presence
  hasDuplicate = !support.detectDuplicates;
    sortInput = !support.sortStable && results.slice( 0 );
  results.sort( sortOrder );
  if ( hasDuplicate ) {
    while ( (elem = results[i++]) ) {
      if ( elem === results[ i ] ) {		  //用===
        j = duplicates.push( i );
      }
    }
    while ( j-- ) {
      results.splice( duplicates[ j ], 1 );   //用splice實作
    }
  }
  // Clear input after sorting to release objects
  // See https://github.com/jquery/sizzle/pull/225
  sortInput = null;
  return results;
};
           
//jquery1.8.3
jQuery.unique = Sizzle.uniqueSort;
Sizzle.uniqueSort = function( results ) {
  var elem,
    duplicates = [],
    i = 1,
    j = 0;
  hasDuplicate = baseHasDuplicate;
  results.sort( sortOrder );
  if ( hasDuplicate ) {
    for ( ; (elem = results[i]); i++ ) {
      if ( elem === results[ i - 1 ] ) {
        j = duplicates.push( i );
      }
    }
    while ( j-- ) {
      results.splice( duplicates[ j ], 1 );
    }
  }
  return results;
};
           

對應紅色的字型為新增或者修改的,然而并看不出什麼,調試一下進入,會發現問題居然在sortOrder上!坑啊!繼續找~~~

js與jquery常用方法總結
//jquery1.11.0
//定義時
sortOrder = function(a, b) {
  if (a === b) {
    hasDuplicate = true;
  }
  return 0;
};
//setDocument裡面
sortOrder = hasCompare ?
  function(a, b) {
    // Flag for duplicate removal
    if (a === b) {
      hasDuplicate = true;
      return 0;
    }
    // Sort on method existence if only one input has compareDocumentPosition
    var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
    if (compare) {
      return compare;
    }
    // Calculate position if both inputs belong to the same document
    compare = (a.ownerDocument || a) === (b.ownerDocument || b) ?
      a.compareDocumentPosition(b) :
      // Otherwise we know they are disconnected
      1;
    // Disconnected nodes
    if (compare & 1 ||
      (!support.sortDetached && b.compareDocumentPosition(a) === compare)) {
      // Choose the first element that is related to our preferred document
      if (a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a)) {
        return -1;
      }
      if (b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b)) {
        return 1;
      }
      // Maintain original order
      return sortInput ?
        (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) :
        0;
    }
    return compare & 4 ? -1 : 1;
  } :
  function(a, b) {
    // Exit early if the nodes are identical
    if (a === b) {
      hasDuplicate = true;
      return 0;
    }
    var cur,
      i = 0,
      aup = a.parentNode,
      bup = b.parentNode,
      ap = [a],
      bp = [b];
    // Parentless nodes are either documents or disconnected
    if (!aup || !bup) {
      return a === doc ? -1 :
        b === doc ? 1 :
        aup ? -1 :
        bup ? 1 :
        sortInput ?
        (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) :
        0;
      // If the nodes are siblings, we can do a quick check
    } else if (aup === bup) {
      return siblingCheck(a, b);
    }
    // Otherwise we need full lists of their ancestors for comparison
    cur = a;
    while ((cur = cur.parentNode)) {
      ap.unshift(cur);
    }
    cur = b;
    while ((cur = cur.parentNode)) {
      bp.unshift(cur);
    }
    // Walk down the tree looking for a discrepancy
    while (ap[i] === bp[i]) {
      i++;
    }
    return i ?
      // Do a sibling check if the nodes have a common ancestor
      siblingCheck(ap[i], bp[i]) :
      // Otherwise nodes in our document sort first
      ap[i] === preferredDoc ? -1 :
      bp[i] === preferredDoc ? 1 :
      0;
  };
           

View Code in jquery1.11.0

js與jquery常用方法總結
//jquery 1.8.3
sortOrder = docElem.compareDocumentPosition ?
  function( a, b ) {
    if ( a === b ) {
      hasDuplicate = true;
      return 0;
    }
    return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
      a.compareDocumentPosition :
      a.compareDocumentPosition(b) & 4
    ) ? -1 : 1;
  } :
  function( a, b ) {
    // The nodes are identical, we can exit early
    if ( a === b ) {
      hasDuplicate = true;
      return 0;
    // Fallback to using sourceIndex (in IE) if it's available on both nodes
    } else if ( a.sourceIndex && b.sourceIndex ) {
      return a.sourceIndex - b.sourceIndex;
    }
    var al, bl,
      ap = [],
      bp = [],
      aup = a.parentNode,
      bup = b.parentNode,
      cur = aup;
    // If the nodes are siblings (or identical) we can do a quick check
    if ( aup === bup ) {
      return siblingCheck( a, b );
    // If no parents were found then the nodes are disconnected
    } else if ( !aup ) {
      return -1;
    } else if ( !bup ) {
      return 1;
    }
    // Otherwise they're somewhere else in the tree so we need
    // to build up a full list of the parentNodes for comparison
    while ( cur ) {
      ap.unshift( cur );
      cur = cur.parentNode;
    }
    cur = bup;
    while ( cur ) {
      bp.unshift( cur );
      cur = cur.parentNode;
    }
    al = ap.length;
    bl = bp.length;
    // Start walking down the tree looking for a discrepancy
    for ( var i = 0; i < al && i < bl; i++ ) {
      if ( ap[i] !== bp[i] ) {
        return siblingCheck( ap[i], bp[i] );
      }
    }
    // We ended someplace up the tree so do a sibling check
    return i === al ?
      siblingCheck( a, bp[i], -1 ) :
      siblingCheck( ap[i], b, 1 );
  };
           

View Code in jquery 1.8.3

很多是不是?有木有覺得瞬間被我坑了?啊哈,其實隻要繼續調試的時候斷點設定好,你就會發現~~~沒有比這更坑的了!它們都是循環的!1.8.3裡面就在第一個function裡面轉來轉去,手都點酸了也沒看到出來,1.11.0整體循環,有參數的個數那麼多次。

最後的結論是:還是不要用這個不靠譜的函數了。如果需要類似的功能,用原生js手動寫就好。同時說明了關注更新的重要性,不過程式猿也不一定有那麼長的時間去關注每一次的更新,那麼就一定要準确的了解自己手頭的版本,最好是空閑時對用到的功能測試一下,看下源碼,網上得來終覺淺啊~

6.判斷

$.inArray(val,arr)  判斷val是否在arr裡面

var a = [1, 2, 3, 4];
$.inArray(2, a);     //有的話傳回下标,沒有的話傳回-1      
//對應源碼
inArray: function(elem, arr, i) {
  var len;
  if (arr) {
    if (indexOf) {
      return indexOf.call(arr, elem, i);	 //實際實作
    }
    len = arr.length;
    i = i ? i < 0 ? Math.max(0, len + i) : i : 0;
    for (; i < len; i++) {
      // Skip accessing in sparse arrays
      if (i in arr && arr[i] === elem) {	 //一般盡可能用===而杜絕==可能帶來的隐式轉換
        return i;
      }
    }
  }
  return -1;
}
           

7.元素轉數組

$.makeArray()将一個類數組對象轉換為真正的數組對象。(所謂"類數組對象"就是一個正常的Object對象,但它和數組對象非常相似:具備length屬性,并以0、1、2、3……等數字作為屬性名。不過它畢竟不是數組,沒有從數組的原型對象上繼承下來的内置方法(例如:push()、 sort()等)。)

    $.toArray()将所有DOM元素恢複成數組。(其實用選擇器取的時候就是很自然的數組的形式)

這兩個實際用得太少了就不具體分析了,知道有這玩意就行吧。

三.補充

1.清空數組

方法1:length設為0 (js身為弱變量類型語言的展現之一,array的length屬性可寫)(效率比較低)

方法2:直接指向[]的引用 (如閉包銷毀指向null一樣,垃圾回收會自動回收空間)(效率比較高)

2.相容性

IE8下

$.inArray 代替 indexOf

$.grep代替Array.prototype.filter

3.注意事項

一般情況下用$.functionName(obj,callback)的形式調用jquery方法的相容性比較好,比如我曾遇到IE8及以下不能識别$(dom).val().trim()的情況,顯示trim is not a function,然而改為$.trim($(dom).val())就沒問題。

前面那種情況實際是string調用trim方法(如果加上call或者apply注入trim方法可以過,但是必要嘛?),後面是jquery對象調用trim方法。

最後再啰嗦一句,歡迎大家的意見和建議,幫我糾錯,共同進步,謝謝!