大家都知道javascript中的 call 和 apply 是很有用的。不懂的自行百度。
看到别人用内置的函數處理一個自定義的對象我們都會感到非常的崇拜。比如 删除obj 中前五個和後五個資料
[].slice.call(obj,5,-5)
。對于Array的原型中的函數(不限于Array),Ecmascript标準中也是有這樣的描述:
xxx 函數被有意設計成通用的;它的 this 值并非必須是數組對象。是以,它可以作為方法轉移到其他類型的對象中。一個宿主對象是否可以正确應用這個 splice 函數是依賴于實作的。
我們疑惑的是一個對象具有什麼樣的屬性才可以調用一些内置的函數呢。這個就需要我們去查閱Ecmascript 協定标準,可是大家都懂得,标準寫的還是很有技術水準的,不是一時半會兒可以看得懂的。
是以我就根據Ecmascript的标準寫出了Array.prototype(目前隻寫了這個,以後補充)中函數近似等價的javascript函數,當然并不能完全等價,可是大部分還是盡量貼近原始函數的實作。當然隻能貼近有些功能是不能用javascript中語句實作的。
結果你會發現,其實一個對象基本是隻要有
length
屬性就可以使用這個對象作為
Array.prototype
中函數的
this
執行而不出錯,而且
length
屬性不必非要是數字。隻要可以轉換成整型就可以。
另一點就是可以讓大家知道一個功能的具體作用,沒有什麼比計算機語言更嚴謹的描述了。
未經測試,難免有所疏漏,請大家予以指正。
Array.prototype.constructor = Array;
Array.prototype.toString = function(){
//需要的屬性 join
var array = this; // toObject 後面這樣的注釋都表示強制類型轉換
var func = array.join;
// if (! func instanceof Function) {throw "type Error"}
return func.call(array);
};
Array.prototype.concat = function (item1)
{
var O = this; // toObject
var A = []; var n = ;
var items = [O];var i;
for(i = ; i < arguments.length; i++) {
items.push(arguments[i]); // 标準裡沒有使用push實作這個,隻是為了表達标準裡的意思,後面相同
}
while(items.length){
var E = items.shift(); //标準裡寫的不是shift函數實作這個,後面相同
if(E instanceof Array){
var k = ; var len = E.length;
while(k < len){
if(E.hasOwnPropery(k.toString())){
A[n] = E[k];
}
n++; k++;
}
}else{
A[n] = E;
n++;
}
}
return A;
};
Array.prototype.join = function(sepatator)
{
var O = this; // toObject
var lenVal = O.length;
var len = lenVal; //toUint32
sepatator = sepatator || ",";
var sep = sepatator.toString();
if(len === ) { return ""; }
var element0 = O[];
var R = element0 === undefined || element0 === null ? "" : element0.toString();
var k = ;
while(k < len){
var S = R + sep;
element = O[k];
var next = element === undefined || element === null ? "" : element.toString();
R = S + next;
k++;
}
return R;
};
Array.prototype.pop = function (){
var O = this; // toObject
var lenVal = O.length;
var len = lenVal; // 強制類型轉換toUint32;
if(len === ){
O.length = ;
return undefined;
}
var element = O[len-];
delete O[len-]; //對于數組,這句可以沒有,但是對于obj這是必須的
O.length = len-;
return element;
};
Array.prototype.push = function(item1) {
var O = this ; //toObject
var lenVal = O.length;
var n = lenVal; // toUint32;
var items = [O];var i;
for(i = ; i < arguments.length; i++) {
items.push(arguments[i]); // 标準裡沒有使用push實作這個
}
while(items.length > ){
var E = items.shift();
O[n] = E;
n++;
}
O.length = n;
return n;
};
Array.prototype.reverse = function () {
var O = this; //toObject
var lenVal = O.length;
var len = lenVal; // toUint32
var middle = Math.floor(len/);
var lower = ;
while(lower !== middle){ //不知道為什麼标準裡寫的不是 lower >= middle
var upper = len - lower - ;
var lowerValue = O[lower];
var upperValue = O[upper];
if(O.hasOwnPropery(lower.toString()) && O.hasOwnPropery(upper.toString())){
O[lower] = upperValue;
O[upper] = lowerValue;
}else if(!O.hasOwnPropery(lower.toString()) && O.hasOwnPropery(upper.toString())){
O[lower] = upperValue;
delete O[upper] ;
}else if( O.hasOwnPropery(lower.toString()) && !O.hasOwnPropery(upper.toString()) ){
delete O[lower];
O[upper] = lowerValue;
}
lower++;
}
return O;
};
Array.prototype.shift = function (){
var O = this; //toObject
var lenVal = O.length;
var len = lenVal; // toUint32
if(len === ) { O.length = ; return undefined; }
var first = O[];
var k =;
while(k < len){
var from = k.toString();
if(O.hasOwnPropery(from)){
O[k-] = O[k];
}else{
delete O[k-];
}
k++;
}
delete O[k-];
O.length = len - ;
return first;
};
Array.prototype.slice = function (start, end){
var O = this; //toObject
var A = [];
var lenVal = O.length;
var len = lenVal; // toUint32
var relativeStart = start; // toIntger
var k = relativeStart < ? Math.max(len + relativeStart,):Math.min(relativeStart,len);
var relatveEnd = typeof end ==="undefined" ? len : end; // toIntger(end)
var final_ = relatveEnd < ? max(len+relatveEnd,) : min(relativeEnd,len);
var n = ;
while(k < final_){
if(O.hasOwnPropery(k.toString())){
A[n] = O[k];
}
k++;n++;
}
return A;
};
Array.prototype.sort = function (){
};
Array.prototype.splice = function (start,deleteCount) {
var O = this; //toObject
var A = [];
var lenVal = O.length;
var len = lenVal; // toUint32
var relatveStart = start; // toIntger
var actualStart = relatveStart < ? Math.max(len + relatveStart,): Math.min(relatveStart,len);
var actualDeleteCount = Math.min(max(deleteCount,),len - actualStart); //toIntger(deleteCount)
var k = ;
var from;
while(k < actualDeleteCount){
from = (actualStart+k).toString();
if(O.hasOwnPropery(from)){
A[k] = O[actualStart+k];
}
k++;
}
var items = [];
for(i = ; i < arguments.length; i++) {
items.push(arguments[i]); // 标準裡沒有使用push實作這個
}
var itemCount = items.length;
if(itemCount < actualDeleteCount){
k = actualStart;
while(k < len - actualDeleteCount){
from = (k+actualDeleteCount).toString();
if(O.hasOwnPropery(from)){
O[k+itemCount] = O[k+actualDeleteCount];
}else{
delete O[k+itemsCount];
}
k++;
}
k = len;
while(k > len-actualDeleteCount + itemsCount){
delete O[k-];
k--;
}
}else if(itemCount > actualDeleteCount){
k = len - actualDeleteCount;
while(k > actualStart){
from = (k+actualDeleteCount - ).toString();
if(O.hasOwnPropery(from)){
O[k + itemCount - ] = O[k+actualDeleteCount -];
}else{
delete O[k + itemCount -];
}
k--;
}
}
k = actualStart;
while(items.length>){
var E = items.shift();
O[k] = E;
k++;
}
O.length = len - actualDeleteCount + itemCount;
return A;
};
Array.prototype.unshift = function (item1){
var O = this; //toObject
var lenVal = O.length;
var len = lenVal; // toUint32
var argCount = arguments.length;
var k = len;
while(k > ){
var from = (k-).toString();
if(O.hasOwnPropery(from)){
O[k + argCount - ] = O [k-];
}else{
delete O[k + argCount -];
}
k--;
}
var j = ;
var items = []; var i;
for(i = ; i < arguments.length;i++){
items.push(arguments[i]);
}
while(items.length > ){
var E = items.shift();
O[j] = E;
j++;
}
O.length = len + argCount;
return len+argCount;
};
Array.prototype.indexOf = function (searchElement){
var O = this; //toObject
var lenVal = O.length;
var len = lenVal; // toUint32
if(len === ) { return -; }
var n = arguments.length >= ? arguments[] : ; //toIntger(arguments[1])
if(n > len) { return -; }
var k = n>= ? n : Math.max(len + n, );
while(k < len){
if(O.hasOwnPropery(k.toString)()){
if(searchElement === O[k]) {
return k;
}
}
k++;
}
return -;
};
Array.prototype.lastIndexOf = function (searchElement){
var O = this;
var lenVal = O.length;
var len = lenVal; // toUint32
if(len === ) { return -; }
var n = arguments.length >= ? arguments[] : ; //toIntger(arguments[1])
var k = n>= ? min(n,len-) : len + n;
while(k >= ){
if(O.hasOwnPropery(k.toString)()){
if(searchElement === O[k]) {
return k;
}
}
k++;
}
return -;
};
Array.prototype.every = function (callbackfn){
var O = this; //toObject
var lenVal = O.length;
var len = lenVal; // toUint32
//if(! callbackfn instanceof Function) {throw "typeerror"}
var T = arguments.length >= ? arguments[] : undefined;
var k = ;
while(k < len){
if(O.hasOwnPropery(k.toString())){
var testResult = callbackfn.call(T,O[k],k,O);
if(!testResult) { return false; }
}
k++;
}
return true;
};
Array.prototype.some = function (callbackfn){
var O = this; //toObject
var lenVal = O.length;
var len = lenVal; // toUint32
//if(! callbackfn instanceof Function) {throw "typeerror"}
var T = arguments.length >= ? arguments[] : undefined;
var k = ;
while(k < len){
if(O.hasOwnPropery(k.toString())){
var testResult = callbackfn.call(T,O[k],k,O);
if(testResult) { return true; }
}
k++;
}
return false;
};
Array.prototype.forEach = function(callbackfn){
var O = this; //toObject
var lenValue = O.length;
var len = lenVal; // toUint32
//if(! callbackfn instanceof Function) {throw "typeerror"}
var T = arguments.length >= ? arguments[] : undefined;
var k = ;
while( k < len ){
if(O.hasOwnPropery(k.toString())){
callbackfn.call(T,O[k],k,O);
}
k++;
}
return undefined;
};
Array.prototype.map = function(callbackfn){
var O = this; //toObject
var lenValue = O.length;
var len = lenVal; // toUint32
//if(! callbackfn instanceof Function) {throw "typeerror"}
var T = arguments.length >= ? arguments[] : undefined;
var A = [];
var k = ;
while( k < len ){
if(O.hasOwnPropery(k.toString())){
A[k] = callbackfn.call(T,O[k],k,O);
}
k++;
}
return A;
};
Array.prototype.filter = function(callbackfn){
var O = this; //toObject
var lenValue = O.length;
var len = lenVal; // toUint32
//if(! callbackfn instanceof Function) {throw "typeerror"}
var T = arguments.length >= ? arguments[] : undefined;
var A = [];
var k = ;
var to = ;
while( k < len ){
if(O.hasOwnPropery(k.toString()) ){
if( callbackfn.call(T,O[k],k,O) ){
A[to] = O[k];
to++;
}
}
k++;
}
return A;
};
Array.prototype.reduce = function (callbackfn){
var O = this; //toObject
var lenValue = O.length;
var len = lenVal; // toUint32
//if(! callbackfn instanceof Function) {throw "typeerror"}
//if(len === 0 && arguments.length < 2 ) {throw "type error"}
var k = ;
var accumulator;
if(arguments.length > ) {
accumulator = arguments[];
}else{
var kPresent = false;
while(kPresent === false && k < len){
kPresent = O.hasOwnPropery(k.toString());
if(kPresent){
accumulator = O[k];
}
k++;
}
// if(!kPresent) {throw "type error"}
}
while( k < len ){
if(O.hasOwnPropery(k.toString())){
accumulator = callbackfn.call(undefined,accumulator,O[k],k,O);
}
k++;
}
return accumulator;
};
Array.prototype.reduceRight = function (callbackfn){
var O = this; //toObject
var lenValue = O.length;
var len = lenVal; // toUint32
//if(! callbackfn instanceof Function) {throw "typeerror"}
//if(len === 0 && arguments.length < 2 ) {throw "type error"}
var k = len - ;
var accumulator;
if(arguments.length > ) {
accumulator = arguments[];
}else{
var kPresent = false;
while(kPresent === false && k >= ){
kPresent = O.hasOwnPropery(k.toString());
if(kPresent){
accumulator = O[k];
}
k--;
}
// if(!kPresent) {throw "type error"}
}
while( k >= ){
if(O.hasOwnPropery(k.toString())){
accumulator = callbackfn.call(undefined,accumulator,O[k],k,O);
}
k--;
}
return accumulator;
};