Javascript: recreating Array.from? - javascript

I came across this code for stripping Marketo forms of their included stylesheets. Let's assume that the code author is a super senior engineer. Array.from() could have been used instead of defining arrayFrom (functionally at any rate), so why use the latter?
For my part I'm trying to understand the arrayFrom definition (first line of the codeblock):
bind() sets this to the provided value, here [].slice (why?)
call() allows us to call getSelection with the this value bound by bind.
getSelection() returns a Selection object (or string in Firefox) of the selected text. This I'm unsure about.
In its use, arrayFrom gets passed an array (or NodeList) of stylesheets and returns an array of the same stylesheets (a shallow copy thereof?) no differently than if Array.from were used, so the functional bit of bind and call must be to alter the this value in a desirable way. Not sure how that acts on [].slice though.
Anyone? I'm clearly missing something.
const arrayFrom = getSelection.call.bind([].slice);
// remove element styles from <form> and children
const styledEls = arrayFrom(formEl.querySelectorAll("[style]")).concat(
formEl
);
styledEls.forEach(function (el) {
el.removeAttribute("style");
});
// create an array of all stylesheets in document
const styleSheets = arrayFrom(document.styleSheets);
// loop through stylesheets and check for ownerNode properties on each
styleSheets.forEach(function (ss) {
if (
//array of <link/> elements tied to stylesheets
[mktoForms2BaseStyle, mktoForms2ThemeStyle].indexOf(ss.ownerNode) !=
-1 ||
formEl.contains(ss.ownerNode)
) {
ss.disabled = true;
}
});

Nowadays we would just use Array.from. But your questions are about the construct that is used:
const arrayFrom = getSelection.call.bind([].slice);
First of all, this has nothing to do with getSelection, as the expression is not binding that, but the call function. This call function is on the Function prototype, so the above leads to the same result as:
const arrayFrom = Function.prototype.call.bind(Array.prototype.slice);
call is a function that allows one to call another function with the possibility to provide a this-argument to it. Here we define that the function to be called should be slice. The first argument we will provide to arrayFrom will be like the first argument we would provide to call, i.e. the object on which slice should be called. This gives it a similar behaviour as Array.from.
It may help to replace bind by this function that does a similar thing:
function arrayFrom(arrayLike) {
return Function.prototype.call.call(Array.prototype.slice, arrayLike);
}
It is confusing, but we invoke call with call so that we can provide a this argument to it (defining the function we want to call), making the second argument the this-argument that call (the first one) deals with.

Related

Constructor function to create DOM elements

I'm trying to use a constructor function to help create DOM elements but I'm wondering if there was a preferred way to do so. I know I could use a framework to do with this but I'd like to implement it using vanilla JavaScript.
Both ways shown below seem to work but I haven't used the new operator with functions very much. Is there any difference between the two ways? Would I be better just to use a plain old function in this situation and not use new?
// First way
function Title(text){
this.element = document.createElement('h2');
this.element.innerText = text;
return this.element;
}
// Second way
function Title(text){
var element = document.createElement('h2');
element.innerText = text;
return element;
}
var title = new Title("Hello");
document.body.appendChild(title);
Your first way does't seem to be correct. Though it works, you seems you haven't understood how new works in JavaScript. When you use new with a function, the following steps are taken:
An empty object is created, something like {}.
All this references inside the function refer to that empty object.
this is used to populate that empty object as needed.
implicitly this is returned. (If you explicitly return, this will be ignored.)
Note that in a constructor function, if you explicitly return something other than this, the returned value is not instanceof that constructor function. Only this is instanceof the constructor function.
Therefore, the first way has nothing to do with logic of new. It's logically the same as the second one.

function like map() that doesn't create a new array

Is there a function like map() in JS that stores the returns in the original array, instead of making a new array? If not, what would be the most efficient way to do this?
Just use .forEach() instead:
myArray.forEach(function(value, index, array) {
array[index] = ... // some mutation of value
});
The exact same code would still work with .map (which invokes the callback with the same three parameters and therefore allows in-place mutation) but .forEach avoids the overhead of creating a new array, only to have it thrown away again immediately.
Note also that whilst one could just refer to myArray inside the callback, it's much more efficient not to. Having the array parameter passed to the callback allows the callback to manipulate or access the original array without requiring it to be in the lexical scope (although using this to insert or delete elements would be ill advised)

Calling a no param javascript function with a param

Does javascript not check function parameters when invoking.
This function "test" below fires even though it is being called with no parameter.
<input type="button" value="test" onclick="test()">
test = function(param){
alert("test");
}
fiddle :
http://jsfiddle.net/Yazpj/1912/
Should an error not being thrown or does the javascript engine/parser not even check function parameters when finding what to call. Does this have any implications for overriding functions ?
No, JavaScript does not check parameters.
Extra parameters will be ignored. Parameters declared but not passed will have a value of undefined. All passed parameters (declared or otherwise) will appear in the arguments pseudo-array.
There are no implications for overriding functions because JS does not support overriding functions.
Libraries such as jQuery that have methods with multiple signatures use a single function that figures out the type of the passed parameters and then performs the required action.
You have to check on your own:
var test = function (param) {
if (typeof param === 'undefined') {
// do something...
}
};
Javascript is a really flexible language and this is just one example of it. Unless you are not accessing the param it won t rise any error e.g. param.sender
As for your override question it is sort of true. Every Javascript function has a arguments variable which is the array of passed parameters. if you give name the parameter defining the function JS just give it to you according to order.
But overriding is another story the overriding is achieved by checking the arguments element sometimes just length of the array sometimes type of the individual item.
For example; when you call $("#name").val() as there is no item it just return the value if arguments has values this time jQuery user proper assignment e.g. element.value = arguments[0]

RaphaelJS Set.forEach()

I read in the documentation raphaeljs description of Set.forEach, and can't understand
how it works. Please can anyone give me an example of usage.
Here you have a working example:
http://jsfiddle.net/9X6rM/
And this is the important part of It:
set.forEach(function(e){
e.attr({fill:'#000'})
})
Its a little bit tricky at first, but its pretty handy when you get it. You need to pass to the forEach() method the function that you want to execute on each element, and this function need to have, like an argument, a variable name to bind to the element. So in this case e is the rectangle that is being processed. Got it?
This thread is pretty helpful in understanding how forEach works
Edit :
You have a working example in the Raphaƫl Documentation
Raphael.el.red = function () {
this.attr({fill: "#f00"});
};
Raphael.st.red = function () {
this.forEach(function (el) {
el.red();
});
};
// then use it
paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red();
Some things that are missing from the Raphael forEach documentation:
What is passed to the function you define
set.forEach(function(element, index){
element.attr({fill:'#000'});
alert('This is the element that can be accessed as set['+index+']');
})
Two arguments are passed passed to the callback function:
The Raphael element that is currently being looked at.
The index number indicating the position of that Raphael element in the set.
this in the scope of a cycle of Raphael's forEach is unchanged from the surrounding function (unlike jQuery's .each()).
Possible crashes or unexpected behaviour
Unlike jQuery's .each() function, Raphael's .forEach() crashes out if it's passed a singular Raphael element instead of a set. If a variable might contain one element, or might contain a set of multiple elements, check what type of Raphael object it is first.
As mentioned, Raphael's .forEach() doesn't create a closure like in jQuery - it's really just an iteration through an array. Variables in each iteration aren't 'frozen' in that iteration, they can be overwritten by following iterations.

Backbone.js - Todo Collection - What exactly is happening in this return statement?

I'm looking back at the Backbone todo list and have a question about the collection.
Here is the code:
window.TodoList = Bacbone.Collection.extend({
model: Todo,
localStorage: new Store("todos"),
done: function() {
return this.filter(function(todo){return todo.get("done")})
},
remaining: function() {
return this.without.apply(this, this.done());
}
})
I understand everything that is going on here, except for the 'remaining' function.
The return statement: return this.without.apply(this, this.done()); is using a proxy to an underscore method - _.without
According to Underscore docs, here is what that is for:
without_.without(array, [*values]) Returns a copy of the array with
all instances of the values removed. === is used for the equality
test.
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]
So, I get that it is saying to return everything in the collection without a 'done' attribute with the value of 'true'.
What I don't understand is the 'apply' function that is being chained to it. That doesn't appear in the Backbone docs or the Underscore docs. At least not anywhere I can find it.
Can anyone explain in detail what is going on with those elements in the Return statement?
this is referring to the collection.
apply is a method of javascript functions that allows you to set context of a method and send an array of values to the caller.
apply expects context as the first parameter then an array or array-like (such as arguments) which will be passed in as parameters the function.
You can do the same thing with .call except the 2nd+ params are comma separated.
apply and call are native to javascript.
So...
return this.without.apply(this, this.done());
the method this.done() returns an array, but uses the context of the collection and passes in a series of values to be ignored via the without method. Which in turn returns all todos that aren't done within the collection.
Example:
_.without([1,2,3,4],1,2); === _.without.call([], [1,2,3,4], 1, 2);
My understanding is that, in this case, the use of apply is redundant, remaining could be shortened as follows:
remaining: function() {
return this.without(this.done());
}
As I understand it, the only reason to use apply is if you want (or need) to change the contextual item that without will operate on. In this case, we have no need to do that.
If I'm wrong, I'd really (really!) like to have an explanation of why apply is necessary here.
apply invokes a function and binds this in the context of that function to the first argument passed (in this case, the Collection instance TodoList). The second argument is an array of arguments to be passed to without.
By the way, apply isn't a Backbone thing -- it's native to JavaScript.
The reason for this
this.without.apply(this, this.done())
is that "_.without" does not accept as argument the array of items to be excluded as a single array ([]) argument
See here _.without to accept array as second argument
apply, which is part of the JS Function.prototype, here is a workaround to inject the excluding items in a single array argument
the use of apply in this case is redundant because backbone collections is doing the job correctly cf. http://backbonejs.org/docs/backbone.html#section-122
we can use underscore like this: _.without.apply(this, this.done()) or backbone binding like this: this.without(this.done) by using backbone bind.
Please take a look at underscore doc :
like this :
without_.without(array, [*values])
Returns a copy of the array with all instances of the values removed.
_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]
I changed the function to this and got the exact same result on the TODO list application:
remaining: function () {
return this.filter(function (todo) {
return !todo.get('done');
});
}
I still didn't understand how apply became a method of without, I knew apply was a Javascript function, but then I read the documentation for apply and understood that in this case without was being used in an object-oriented way (see http://underscorejs.org/#chain).
In fact, apply could be passed null instead of this as the context and it wouldn't change the result because it's not being used at all:
return this.without.apply(null, this.done());
Notice the first this is the actual collection of models and without, via the second argument in apply, which is the array of done (completed) tasks, is producing the array of pending todo tasks.
By the way, the latest version of the TODO application renames the function done to completed.
Here this.without() delegates to _.without() function. _.without() needs an array and elements as parameters not as an array. By using apply() , apply calls _.without() in the correct manner.
var obj = {
f1: function(a,b,c){}
};
Now obj.f1(1,2,3) == obj.f1.apply(obj, [1,2,3]).
With this infomation, this.without(this.complete()) passes an array to the without method. But without method needs individual elements to be passed as arguments. That can be done using Function.apply().
The without function needs a list of elements to remove from this.
this.completed() returns an array, therefore it is not what without function is expecting.
apply is a native JavaScript function, which calls a function setting the this context as the first argument and an array as the second argument. The argument is passed to the original function as its list arguments.
In this case apply passes the arguments to without in this.completed(), meeting the expectation of without.
In conclusion, in this case, apply is necessary.
Sorry, I'm a total newb # this stuff, but couldn't fn.remaining (also) be declared as:
return this.filter(function(todo){return !todo.get("done")})
Stating this as a request for clarification, rather than an alternative declaration :)
(edit: couldn't bold the '!' before 'todo.get...')

Categories