大家都知道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;
};