简体   繁体   中英

array.splice = what does it means?

I would like to understand the meaning of that code fragment. "saveTo" is a array, the programmer assigned a function() to the splice method. I don't understand what does it mean. Is that a override? What is the meaning of the return argument?, and why the function takes no argument while splice requires 2 or more arguments?

    saveTo.splice = function() {
        if (saveTo.length == 1) {
            $("#send").prop("disabled", true);
        }
        return Array.prototype.splice.apply(this, arguments);
    };

Javascript lets you re-assign methods at runtime. In this case, what the programmer was doing is reassigning splice on this specific instance of an array in order to call a jQuery method. Beyond that, it works in exactly the same way as the existing splice as they are calling return Array.prototype.splice.apply(this, arguments); - meaning that this method just passes on whatever arguments are passed to it.

Here's a demo:

 var myArray = [1,2,3,4]; console.log("Splice before re-assing: ", myArray.splice(1,1)); // reset it. myArray = [1,2,3,4]; myArray.splice = function(){ console.log("From inside new splice function"); return Array.prototype.splice.apply(this, arguments); } console.log("Splice after re-assiging: ", myArray.splice(1,1)); 

Whether this is a good thing to do is debatable. It breaks a few principles of programming.

The programmer that wrote this code knew that some other part of the program is calling splice on this array, and he wanted to attach an event to that, in order to update the user interface (hence the call to jQuery).

This is commonly called "Monkey Patching". You can read about it at https://www.audero.it/blog/2016/12/05/monkey-patching-javascript/

This is not a good pratice as it obfuscate what is happening: no programmer would expect that calling a data manipulation function has side-effects somewhere else.

You can run this sample to understand how it works:

const myArray = [];

// Patch push method only for this instance of array.
myArray.push = function() {
   // log event
   console.log('myArray.push was called with the following arguments', arguments);

   // Call the original push function with the provided arguments.
   return Array.prototype.push.apply(this, arguments);
}

myArray.push(1);

You can also patch methods for all instances of a given class:

// Patch push method on all arrays
const originalPush = Array.prototype.push;
Array.prototype.push = function() {
   // log event
   console.log('.push was called with the following arguments', arguments);

   // Call the original push function with the provided arguments.
   return originalPush.apply(this, arguments);
}

const myArray = [];
myArray.push(1);

As for your question about the arguments , in javascript all functions can access the arguments array-like object that contains the arguments the function was called with, which does not depend on which arguments are specified in the original declaration.

function doSomething(arg1) {
   console.log(arguments[2]);
}

doSomething(1, 2, 3); // outputs "3"

Here is the MDN documentation about it: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

Note that there is a better way to extend arrays in ES6:

 class CustomArray extends Array {
   splice(...args) {
      if(this.length === 1) {
         $("#send").prop("disabled", true);
      }
      super.splice(...args);
   }
}

Now that there are other ways to change the arrays length, .length , .pop , .shift , etc. so those should be overriden as well. However then it is still questionable wether the code calling those methods should not just cause the side effect.

What this does is it adds some checks for specifically saveTo.splice . If you call anyOtherArray.splice , then it'll just be evaluated as per normal. The reason it takes no arguments is because Array.prototype.splice takes arguments, and also the calling context of saveTo , as well as the array-like objects arguments , representing all the arguments passed to saveTo.splice . So it's just adding a little bit of extra code based on a specific condition - other than that, there's no difference to the native splice .

1) Yes, the programmer has overridden splice method, its not recommended

2) return statement is nothing but calls Array.prototype.splice(the original method).

3) Yes, splice requires arguments, but in JS, you may not define them as function params. You get the passed parameters as an array like object arguments inside your functions, if you look closely, they call Array.prototype.splice with this and arguments object.

Okay, let's dissect this piece by piece.

saveTo.splice = function() {
    if (saveTo.length == 1) {
        $("#send").prop("disabled", true);
    }
    return Array.prototype.splice.apply(this, arguments);
};

As we all know that in JavaScript functions are first class objects , so if we have an object let's say saveTo something like this:

const saveTo = {};

Then we can assign a function to one of its properties like :

 saveTo.splice = function() {
 };

or something like this to:

const saveTo = {
   splice: function() {
   }
};

With that out of the way, you are just calling the Array#prototype#splice method to create a shallow copy out of the array and passing it an iterable to it.

So in total you have overridden the native Array#prototype#splice to fit your requirement.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM