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.
Let's say I have a function
var addOneToArray = function(arr) {
return arr.push(1);
};
If arr is always going to be the same in the program (let's say it's always myArray), does it make sense to do this instead:
var addOneToArray = function() {
return myArray.push(1);
};
What I'm wondering is, is there any added value to doing the latter in terms of speed or something else? Or is it better to have a more generic function, that maybe gets reused?
If you have the only method that needs to executed then it would be fine. But when you have to implement multiple methods related to same object (in our case Array object) it is always fine to have own constructor for the same.
You can use something like,
var customArray = function() {}
customArray.prototype = Array.prototype; // Make it to behave like Array
Now, customArray is same as the Array class. You can add your method as
customArray.prototype.addOneToArray = function() {
this.push(1);
};
How you can use it,
var arr = new customArray();
arr.addOneToArray();
My background is more in strongly-typed languages than not, so I will state up front that I have a bias against treating undefined objects in a casual manner. That said, I was considering a simple question of assigning a Boolean value to a variable, where said Boolean comes from the property of some object, and while the object will always exist the property may not.
That sounds more complicated than it really is. Take a look. We start with spinning up some objects early in the code, covering the three possible scenarios:
var object1 = {};
object1.IsDisplayed = true;
var object2 = {};
object2.IsDisplayed = false;
var object3 = {};
// notice we do *not* create the IsDisplayed property here
Sometime later we call the process() function that takes a single argument. Let's call this baseline Solution A.
Solution A
This being JavaScript, that actually works as expected for object1, object2, and object3. But it seems to have a bit of a code smell to me; it is not clear that the author has considered a possibly non-existent property.
function process(renderedItem) {
var rendered = renderedItem.IsDisplayed;
if (rendered) {
// do some stuff here
}
}
I see two possible ways to make this more robust:
Solution B
I like this solution because it is both robust and clear to even the most casual reader that the undefined case has been properly considered. On the downside it is wordy, not nearly as compact as solution C, and it uses a string name of a property, which I have a strong distaste for.
function process(renderedItem) {
var rendered = renderedItem.hasOwnProperty('IsDisplayed')
? renderedItem.IsDisplayed
: false;
if (rendered) {
// do some stuff here
}
}
Solution C
I like this solution because it is robust and compact; it explicitly takes into account a possibly non-existent property; however, it is not nearly as obvious as solution B. I remember early on reading some colleagues' code and thinking,"What the heck?" and suggested deleting the === true as redundant. Also, it still is technically referencing an undefined value (in the case of passing in object3).
function process(renderedItem) {
var rendered = renderedItem.IsDisplayed === true;
if (rendered) {
// do some stuff here
}
}
Is there a clear "best practice" amongst these three variations?
I'm building a Backbone Marionette Application. In Marionette you can do something like:
Marionette.Application.extend({
regions: {
mainRegion: function(){return someCondition?"#A":"#B"},
otherRegion: "#something"
}
})
I'm trying to implement this in my application with custom objects. What is the best way to achieve this?
Currently, I'm checking for every value:
if(typeof obj == "function") {
this.data.obj = obj();
}
else {
this.data.obj = obj;
}
or the corresponding ?: expression.
Is there an easier way to do this?
Underscore has a result method that does exactly what you want (see http://underscorejs.org/#result)
You can find the implementation here: http://underscorejs.org/docs/underscore.html#section-128
There is a potential solution (cue screaming) in adding value() [not to be confused with valueOf()] to every prototype you're interested in.
Function.prototype.value = function () { return this(); }; // Probably should be .call() so you can do arguments if necessary.
String.prototype.value = function () { return this; };
etc.
Then you can use this.data.obj = obj.value() for all calls.
If you're queasy about adding functions to prototypes, this isn't a solution you'd want to use. Otherwise you could write a wrapper function that takes obj as an argument and returns the right thing based on the type.
The duck typing idea proposed by dandavis is also good IMHO.
This sort of thing works in JavaScript
function main() {
return 1;
}
main.sub = function () {
return 2;
};
main(); // 1
main.sub(); // 2
and seems useful for doing stuff like
function props() {
return { color: props.color(), size: props.size() };
}
props.color = function () {
// calculate and return color
};
props.size = function () {
// calculate and return size
};
so that you'd have an easy way to pull in an object of all the props using prop() but if you only need one you can call for it directly. Is that type of setup okay?
Even though it is absolutely legal, I'd say it is the wrong utilization of sub methods. It confuses the function with the return value of said function.
I would say a proper use of submethods within functions is when you want to add metadata for the function. Let's say you want to set a property for the function like documentation or whether you want it to be obfuscated. Then you can set the property for the function instead of the underlying object.
Even though your usage may save some writing, it makes reading the code much harder IMHO. You should always strive for ease of readability, not of writing.
Generally this is probably not good practice:
calling: props.color(); will do the same thing as calling props().color.
What would be a better pattern would be something as follows:
var props = function() {
var theColor = function() {
// calculate the color
};
var theSize = function() {
// calculate the size
};
return {
color: theColor(),
size: theSize()
}
}
var someprops = new props();
You could instead of having for example theColor() as the object for color, you could leave it as the function: So the return would be
return {
color: theColor,
size: theSize
}
The difference being that the props.color == "function" whereas in the previous example props.color would've equaled the result of the function.
That looks useful, but it isn't very obvious what's happening when you use it.
The expression props.color() returns the same as the similar expression props().color, but the performance differs as the latter also calculates the other properties, which are then discarded. It's easy to misuse the feature without noticing, so you should consider using an approach where the usage shows more clearly what's actually happening in the code.