I was reading the source code for pallet.js and came across this.
var ret = (function(proto) {
return {
slice: function(arr, opt_begin, opt_end) {
return proto.slice.apply(arr, proto.slice.call(arguments, 1));
},
extend: function(arr, arr2) {
proto.push.apply(arr, arr2);
}
};
})(Array.prototype);
var slice = ret.slice;
var extend = ret.extend;
Why is this necessary? Why could they not simply write this:
var slice = function(arr,opt_begin,opt_end) {
return Array.prototype.slice.apply(arr,[opt_begin,opt_end]));
}
var extend = function(arr,arr2) {
return Array.prototype.push.apply(arr,arr2);
}
EDIT 1:
In response to the duplicate question. I don't think it is a duplicate, but that question definitely does address my question. So it is an optimization. But won't each one only be evaluated once? So is there really a significant improvement here for two function calls?
Also if we are worried about performance why are we calling proto.slice.call(arguments,1) instead of constructing the array of two elements by hand [opt_begin,opt_end], is slice faster?
Because the syntax is just so much cooler. Plus you can rationalize it's use by telling yourself that it's more DRY. You didn't have to type Array.prototype twice.
I can't be sure what was the original rationale behind that code (only the author knows) but I can see a few differences:
proto is a closed-over local variable, while instead Array is a global. It's possible for a smart enough Javascript engine to optimize access because proto is never changed and thus it could even be captured by value, not reference. proto.slice can be faster than Array.prototype.slice because one lookup less is needed.
passing opt_begin and opt_end as undefined is not the same as not passing them in general. The called function can know if a parameter was passed and happens to be undefined or if instead it wasn't passed. Using proto.slice.call(arguments, 1) ensures that the parameters are passed to slice only if they were actually passed to the closure.
Related
Suppose I've a Set as a lookup table.
const myset = new Set(["key1", "key2", "key3", "keepMe"]);
I wanted to filter another array of some other keys (say mykeys) which are in myset.
const mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"];
Question:
Why do I have to use
const filtered = mykeys.filter(k => myset.has(k))
instead of
const filtered = mykeys.filter(myset.has)
// TypeError: Method Set.prototype.has called on incompatible receiver undefined
i.e., why do I've to create an anonymous lambda function in filter? keys.has has same signature (argument - element, return boolean). A friend told me it's related to this.
Whereas mykeys.map(console.log) works without error (although not being of much use).
I came across this article at MDN and I still don't get why "'myset' is not captured as this". I understand the workaround but not the "why". Can anyone explain it with some details and references in a human friendly way?
Update: Thank you all for the responses. Maybe I wasn't clear about what I'm asking. I do understand the workarounds.
#charlietfl understood. Here's his comment, the thing I was looking for:
Because filter() has no implicit this where as set.has needs to have proper this context. Calling it inside anonymous function and manually adding argument makes the call self contained.
You could use thisArg of Array#filter with the set and the prototype of has as callback.
This pattern does not require a binding of an instance of Set to the prototype, because
If a thisArg parameter is provided to filter, it will be used as the callback's this value. Otherwise, the value undefined will be used as its this value. The this value ultimately observable by callback is determined according to the usual rules for determining the this seen by a function.
const
myset = new Set(["key1", "key2", "key3", "keepMe"]),
mykeys = ["ignoreMe", "keepMe", "ignoreMeToo", "key2"],
filtered = mykeys.filter(Set.prototype.has, myset);
console.log(filtered);
This is a fundamental design decision dating back to the first definition of the JavaScript language.
Consider an object
var myObjet = {
someValue: 0,
someFunction: function() {
return this.someValue;
}
};
Now, when you write
var myValue = myObject.someValue;
You get exactly what you have put in it, as if you had written
var myValue = 0;
Similarly, when you write
var myFunction = myObject.someValue;
You get exactly what you have put in it, as if you had written
var myFunction = (function() {
return this.someValue;
});
...except now, you are not in an object anymore. So this doesn't mean anything. Indeed, if you try
console.log(myFunction());
you will see
undefined
exactly as if you had written
console.log(this.someValue);
outside of any object.
So, what is this? Well, JavaScript decides it as follows:
If you write myObject.myFunction(), then when executing the myFunction() part, this is myObject.
If you just write myFunction(), then this is the current global object, which is generally window (not always, there are many special cases).
A number of functions can inject a this in another function (e.g. call, apply, map, ...)
Now, why does it do this? The answer is that this is necessary for prototypes. Indeed, if you now define
var myDerivedObject = Object.create(myObject);
myDerivedObjet.someValue = 42;
you now have an object based on myObject, but with a different property
someValue
console.log(myObject.someFunction()); // Shows 0
console.log(myDerivedObject.someFunction()); // Shows 42
That's because myObject.someFunction() uses myObject for this, while myDerivedObject.someFunction() uses myDerivedObject for this.
If this had been captured during the definition of someFunction, we would have obtained 0 in both lines, but this would also have made prototypes much less useful.
Let's say there is a function:
const foo = (arg) => { do_something };
Before I run do_something, I actually want to normalize arg to an array because the function accept string or types other than array.
I know it is a bad practice to directly modify the passed argument in a function because it may be mutated and resulted in bugs, which are hard to be debugged. So, I will do something like this:
const foo = (arg) => {
const _arg = Array.isArray(arg) ? [...arg] : [arg];
do_something(_arg)
};
As above, I actually do a shallow copy of that array(arg), and use _arg to do something afterward, and I will ensure not to mutate it (since it just a shallow copy). My question is what if I just don't copy it? i.e.:
const foo = (arg) => {
const _arg = Array.isArray(arg) ? arg : [arg];
do_something(_arg)
};
Will it be different? Or which one is a better/healthier way of coding? Will it affect the garbage collecting or any performance issue?
Thanks for the answer.
IMO, the first approach is recommended, because the second approach often leads to the unexpected issues if do_something causes some side effects.
Will it affect garbage collecting? Yes. With the first approach, _arg will be cleaned because nothing references to it. I'm not sure about performance. It depends on the size of data you handle.
My two cents on your concern is that in a language where there's no immutability by default, I would stick with coding conventions rather than trying to emulate immutability.
That is, if you state that arrays mustn't be modified and if a new element should be pushed or replaced you need to use Array.prototype.concat or array spread operator, I believe that your code will be simpler and easier to follow and maintain.
Also, you might want to use immutable collections like ones provided by ImmutableJS.
To my knowledge, the Symbol primitive in JavaScript ES6 is particularly useful for two things:
Create unique keys for Object properties
Override standard built-in JavaScript Object methods, properties and operators
For example: Symbol.hasInstance is called when (before) instanceof runs
Thus, if we create a custom version of Symbol.hasInstance, we could override the behavior of instanceof
My somewhat basic question is: Why use a Symbol to override these functions? Can't we just override them directly?
For example: Override String.prototype.match() instead of Symbol.match
Edit: Agree with the commenter that overriding instanceof directly would not work, thus using match() as an example instead.
You didn't quite elaborate enough in your question, but from a bit of inference and the comments, it seems like you are be misunderstanding how well-known symbols are used to interact with existing types. That is causing you to misunderstand how they improve over possible ES5 global overwriting solutions.
It's important to understand that the value of String.match is a symbol, not a function for matching. It is almost as if someone had done
Symbol.match = Symbol("match");
at the top of your program to create a new Symbol, and set it as a global property so anyone can access it from anywhere.
This is in contrast with the value of String.prototype.match which is the actual function that is used when developers call "foo".match(...).
You seem to be envisioning String.prototype.match like
String.prototype.match = function(obj) {
return Symbol.match(obj);
};
which is not the case. Looking at a simplified example of the actual implementation may help you understand:
String.prototype.match = function(obj) {
// Any object that has a `Symbol.match` property
// will just call that property. This includes every
// existing RegExp object.
if (obj != null && obj[Symbol.match] !== undefined) {
return obj[Symbol.match](this);
}
// Otherwise create a new regex to match against
// match match using that. This is to handle strings, e.g
// "foo".match("f")
const reg = new RegExp(obj);
return reg[Symbol.match](this);
};
and remember, obj[Symbol.match](this); is not calling Symbol.match(), it is reading a property from obj with the name Symbol.match, and then calling the resulting function.
Why use a Symbol to override these functions?
Hopefully that example makes the reasoning behind this clearer.
var regexp = new RegExp("little");
var result = "a little pattern".match(regexp);
is essentially identical to doing
var regexp = new RegExp("little");
var result = regexp[Symbol.match]("a little pattern");
So why does this matter? Because now when you're designing an API to process text, you aren't limited to doing so with regular expressions. I could make my own whole library as
class MyOwnMatcher {
constructor(word) {
this.word = word;
}
[Symbol.match](haystack) {
return haystack.indexOf(this.word);
}
}
var index = "a little pattern".match(new MyOwnMatcher("little"));
// index === 2
and most importantly, I'm able to do this without having to change any globals. In JS code generally it's considered bad practice to modify globals unless you're polyfilling an officially specced and adopted API. You could implement the above like
var original = String.prototype.match;
String.prototype.match = function(arg) {
if (arg instanceof MyOwnMatcher) return this.indexOf(arg);
return original.apply(this, arguments);
};
but it's extremely ugly, easy to get wrong, and modifies a global object that isn't one that you've defined in your own code.
You can essentially think of well-known symbols as a way to implement an interface defined by a separate piece of code.
I'm often finding myself passing around a lot of parameters from function to function. Looks like this:
ajaxLiveUpdate : function (bindTo, func, interval,
dyn, el, lib_template, locale, what) {
// do sth
}
While I could see that storing these in an object specs would make sense "visually" I'm curious as to the performance implications of creating the object, assinging all the key/val pairs and passing the object around.
Question:
If every ms counts, what is the best and most structured way to shuffle around a large number of function parameters?
Thanks!
I think a good optimizer would make this micro-optimization insignificant. Feel free to use whichever suits your coding style and code reading habits better. If you prefer an object, because it's more compact, go ahead and use an object. If you'd rather spell out arguments expressly, then do that.
There may be some performance overhead when creating and passing object instead of just passing arguments, but I doubt this is going to be your application bottleneck. I would go with an object because of code readability.
Tried it in V8 (node.js v0.10.8).
console.time(44);
var f = function(a,b,c,d,e) {
return a+b+c+d+e;
};
var s = 0;
for(var i=0;i<100000000;++i) {
s += f(i,i*2,i+1,i-1,i*3);
}
console.timeEnd(44);
console.log(s);
~1440ms
console.time(44);
var f = function(x) {
return x.a+x.b+x.c+x.d+x.e;
};
var s = 0;
for(var i=0;i<100000000;++i) {
s += f({a:i,b:i*2,c:i+1,d:i-1,e:i*3});
}
console.timeEnd(44);
console.log(s);
~2236ms
If you pass arguments encapsulated in an object, here is what happens:
In JavaScript, when you are retrieving a value from an object it is the same as you are using the for clause to parse an array. Cause objects in JavaScript are the same as associative arrays. So you will waste your computational time on searching for your values by a key.
Use this option only and only if you have a lot of arguments (5 or more) and it is a nice way to organize them, plus you will gain the ability to pass arguments independent of their rightful placement.
I'm currently reading through this jquery masking plugin to try and understand how it works, and in numerous places the author calls the slice() function passing no arguments to it. For instance here the _buffer variable is slice()d, and _buffer.slice() and _buffer seem to hold the same values.
Is there any reason for doing this, or is the author just making the code more complicated than it should be?
//functionality fn
function unmaskedvalue($input, skipDatepickerCheck) {
var input = $input[0];
if (tests && (skipDatepickerCheck === true || !$input.hasClass('hasDatepicker'))) {
var buffer = _buffer.slice();
checkVal(input, buffer);
return $.map(buffer, function(element, index) {
return isMask(index) && element != getBufferElement(_buffer.slice(), index) ? element : null; }).join('');
}
else {
return input._valueGet();
}
}
The .slice() method makes a (shallow) copy of an array, and takes parameters to indicate which subset of the source array to copy. Calling it with no arguments just copies the entire array. That is:
_buffer.slice();
// is equivalent to
_buffer.slice(0);
// also equivalent to
_buffer.slice(0, _buffer.length);
EDIT: Isn't the start index mandatory? Yes. And no. Sort of. JavaScript references (like MDN) usually say that .slice() requires at least one argument, the start index. Calling .slice() with no arguments is like saying .slice(undefined). In the ECMAScript Language Spec, step 5 in the .slice() algorithm says "Let relativeStart be ToInteger(start)". If you look at the algorithm for the abstract operation ToInteger(), which in turn uses ToNumber(), you'll see that it ends up converting undefined to 0.
Still, in my own code I would always say .slice(0), not .slice() - to me it seems neater.
array.slice() = array shallow copy and is a shorter form of array.slice()
Is there any reason for doing this, or is the author just making the code more complicated than it should be?
Yes there may be a reason in the following cases (for which we do not have a clue, on whether they apply, in the provided code):
checkVal() or getBufferElement() modify the content of the arrays passed to them (as second and first argument respectively). In this case the code author wants to prevent the global variable _buffer's content from being modified when calling unmaskedvalue().
The function passed to $.map runs asynchronously. In this case the code author wants to make sure that the passed callback will access the array content as it was during unmaskedvalue() execution (e.g. Another event handler could modify _buffer content after unmaskedvalue() execution and before $.map's callback execution).
If none of the above is the case then, yes, the code would equally work without using .slice(). In this case maybe the code author wants to play safe and avoid bugs from future code changes that would result in unforeseen _buffer content modifications.
Note:
When saying: "prevent the global variable _buffer's content from being modified" it means to achieve the following:
_buffer[0].someProp = "new value" would reflect in the copied array.
_buffer[0] = "new value" would not reflect in the copied array.
(For preventing changes also in the first bullet above, array deep clone can be used, but this is out of the discussed context)
Note 2:
In ES6
var buffer = _buffer.slice();
can also be written as
var buffer = [..._buffer];