主要是基於原生的JS對數組原型上的方法進行封裝、分析sort方法的功能、分不同情況進行討論。仿sort方法的功能實現對sort方法的封裝 ...
基於原生JS封裝數組原型上的sort方法
最近學習了數組的原型上內置方法的封裝,加強了用原生JS封裝方法的能力,也進一步理解數組方法封裝的過程,實現的功能。雖然沒有深入底層,瞭解源碼。以下解法都是基於個人理解用純原生JS實現的功能。如有不對的地方,可以評論告訴我喲
首先,我們先來看一下sort方法的作用、參數、以及方法的返回值,原有數組是否發生改變
sort方法主要用於數組的排序
參數分為兩種:
- 一種:傳的參數是函數、 (排序主要看函數的返回值)
- 另一種:傳的不是函數、或者不傳(只要傳的不是函數就對原來排序過程不產生影響)
方法的返回值是原來數組排序後的數組
原來數組發生改變,是排序後的數組
其次,我們來看一下sort方法要處理的各種情況之間的比較
情況1:
無參實現對字元串數組的排序
情況2:
無參實現對number類型的數組進行排序
情況3:
無參實現對字元串、number等混合類型的數組的排序
情況4:
帶參實現對number類型的數值數據排序
情況5:
帶參sort()對簡單對象List的自定義屬性排序
情況6:
帶參實現對字元串、number混合類型的數組的排序
sort方法對參數的處理:
情況1:如果參數不是函數,則不影響原來排序過程
情況2:如果參數是函數,則根據回調函數中的返回值進行排序。如果返回值大於0,則交換位置;如果返回值小於0,則不交換位置
如果返回值不是一個數字,則不交換位置
基於以上情況的討論,sort方法實現的核心原理如下:
核心原理:不帶參(以及帶的參數不是函數)的情況下:預設升序排列
不帶參的情況下,直接轉字元串,逐個比較ASCII碼的值
只要有一個是對象{}就不交換
帶參數為函數的情況下:
根據函數的返回值進行比較;如果函數返回值大於0;則交換位置
實現代碼如下:
Array.prototype.mySort = function(fn){
if(Object.prototype.toString.call(fn)==='[object Function]'){
//如果傳進來參數的是函數
for(var i = 0;i<this.length-1;i++){
//遍曆數組,將前後兩項作為實參傳給fn
if(fn.call(this,this[i],this[i+1])>0){
//如果fn執行之後的返回值大於0.就調用swap方法交換位置
var a = this[i],b=this[i+1];
this[i] = swap(a,b).a;
this[i+1] = swap(a,b).b;
//交換之後,如果當前項不是第一項,則當前項(索引為i的項)繼續跟前面的項進行比較
if(i>0){
for(var j = i-1;j>=0;j--){
if(fn.call(this,this[j],this[j+1])>0){
var a = this[j],b=this[j+1];
this[j] = swap(a,b).a;
this[j+1] = swap(a,b).b;
}
}
}
}
}
}else{
//如果不是函數,則按正常排序
//遍曆數組,將前後兩項進行比較
for(var i = 0;i<this.length-1;i++){
var cur = this[i];//當前項
var next = this[i+1];//下一項
if(comASCII(cur,next)){
//當返回true的時候交換,並且交換完成之後,當前項繼續往前比較
this[i] = swap(cur,next).a;
this[i+1] = swap(cur,next).b;
//當前項繼續向前比較
if(i>0){
for(var k = i-1;k>=0;k--){
var cur = this[k];
var next = this[k+1];
if(comASCII(cur,next)){
this[k] = swap(cur,next).a;
this[k+1] = swap(cur,next).b;
}
}
}
}
}
}
//封裝一個交換位置的函數
function swap(a,b){
return {
a:b,
b:a
}
}
//如果不傳參的情況下比較ASCII碼
function comASCII(cur,next){
//全部轉換為字元串、逐項比較ASCII碼
cur = cur.toString();
next = next.toString();
//取長度最大值
var len = cur.length>next.length?next.length:cur.length;
//當前後兩項都不是不是{}類型的數據時,進行比較
if(cur!=='[object Object]'&&next!=='[object Object]'){
for(var j = 0;j<len;j++){
if(!isNaN(cur.charCodeAt(j))&&!isNaN(next.charCodeAt(j))){
//如果二者的ASCII碼都是有效數字
if(cur.charCodeAt(j)>next.charCodeAt(j)){
//如果前一項比後一項當前的ASCII碼大,則返回true,交換位置
return true;
}else if(cur.charCodeAt(j)==next.charCodeAt(j)){
//如果相等直接進入下一輪迴圈
continue;
}else{
//前項比後項小,直接返回false
return false;
}
}
}
if(!isNaN(cur.charCodeAt(len))&&isNaN(next.charCodeAt(len))&&(cur.charCodeAt(len-1)==next.charCodeAt(len-1))){
//比較完之後,如果前一項ASCII還是有效數字,說明前項比後項大,交換
return true;
}
}
//如果上述條件不滿足,則不交換
return false;
}
//返回當前數組
return this;
};