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.
Related
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.
I have written this code (this is a snippet) that doesn't seem to be working. I have isolated it to here.
grab = window.document.getElementById;
grab("blueBox") // i.e. grab("blueBox").onclick [...]
Is it possible to create references to native function in javascript. I am doing something with the grabbed element, I just left it out for example. The grab function doesn't seem to work.
I am using FireFox's most recent version
The way you're doing it will mess up the assignment of the this value for the function.
grab = window.document.getElementById;
grab("blueBox") // i.e. grab("blueBox").onclick [...]
here this will be the global object. Try:
grab.apply(window.document, ["blueBox"])
or in newer browsers:
grab = window.document.getElementById.bind(window.document);
to get directly define what this will be.
The first step here is always the JavaScript console. Firebug is your friend. Tell us the error message if it doesn't mean anything to you.
In the mean time, here is a workaround:
var grab = function(id) { return window.document.getElementById(id); }
function grab(id) {
return window.document.getElementById(id);
}
grab("blueBox");
The reason is because the function getElementById is not being called as a method of document, so its this keyword doesn't reference the right object. Using call as suggested in other answers shows that when this references the document, getElementById works.
Here is the code block a
$('ul.filter li').each(function() {
$(this).click(function(e) { //do something });
});
Here is code block b
$('ul.filter li').click(function(e) { //do something });
Don't these do the same thing? is one better than the other? Which one is the better/faster method?
I would assume block b since it has less code but I want to confirm it here, thanks
The effect you see will be the same, but in the first case, every li element is assigned a new function, as you are creating the function object inside the each callback.
In the second case, there exists only one copy of the event handler, which means it uses less memory over all (although this is probably not measurable).
Internally, click calls on (in jQuery 1.7), which is iterating over the elements via each as well:
return this.each( function() {
jQuery.event.add( this, types, fn, data, selector );
});
This is the case with many jQuery methods (most often noted in the documentation), so you are saving characters and memory by letting jQuery implicitly do this.
They would both have the same effect.
I would prefer the second only because it is more concise and you're creating a single anonymous function to handle the click rather than an anonymous function per element.
For Jquery philosophy, the second is better because it is shorter.
Both are more or less same and give the same results. The second code snippet will also internally run each loop and assign the click handler to each li element.
But yes the second code snippet is very clear and simple.
The second usage is called "implicit iteration" and is one of the cornerstones of jQuery.
For example, in JavaScript Definitive Guide, 6th Ed, p.530 for jQuery Basics:
Despite the power of the each() method, it is not very commonly used,
since jQuery methods usually iterate implicitly over the set of
matched elements and operate on them all. You typically only need to
use each() if you need to manipulate the matched elements in
different ways. Even then, you may not need to call each(), since a
number of jQuery methods allow you to pass a callback function.
in http://jqfundamentals.com/chapter/jquery-basics
Implicit iteration means that jQuery automatically iterates over all
the elements in a selection when you call a setter method on that
selection. This means that, when you want to do something to all of
the elements in a selection, you don't have to call a setter method on
every item in your selection — you just call the method on the
selection itself, and jQuery iterates over the elements for you.
Typically, when the library has this built-in as the standard way of doing it, it will be in general better and faster, or else they wouldn't have built it in.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
jQuery $(this) vs this
In jquery sometimes I find that within a function I have to use $(this) because this won't work:
var listItems = $('li');
listItems.each(function(index) {
$(this).css({
})
})
Any ideas as to the reason why?
$() is the jQuery constructor function
this is a reference to the DOM element of invocation
So basically, you're turning a DOM reference into a jQuery object
In your example, you could also use
listItems.each(function(index, element){
$(element).css({
});
});
..since .each() will pass both, index + element in its callback.
I know I'm a bit late to this thread but I just wanted to bring up the fact that redundant wrapping of DOM objects is one of the most frequently committed crimes against jQuery. Taking care with your jQuery-instance constructing can have tremendous effects performance-wise and it's so easy to do that you have no excuse not to.
Typically, when people have a DOM object (whether it be referenced as this or element) they'll try to wrap it each time they need access to a jQuery method:
jQuery(this).css('a', 'b');
The problem is when you're doing this multiple times:
jQuery(this).css('a', 'b');
jQuery(this).find('span').attr(...);
jQuery(this)....
Every time jQuery() is called, a new jQuery instance is constructed. That kind of operation is expensive and should be avoided if at all possible -- especially in loops!
To avoid this, for one, you could utilise chaining with all methods that return a jQuery instance $(this).css(a,b).attr(a,b)...). The rest of the time you should have a locally declared variable that refers to the jQuery instance and then just use that:
var self = jQuery(this);
self.css(...);
self.attr(...);
If you're doing this within an .each() callback function, there is still a new jQuery object being constructed on every single iteration. You can avoid this by having one generic jQuery object which you continually mutate and then you can run jQuery methods off that single instance:
Look at this:
jQuery.single = function(a){
return function(b){
a[0] = b;
return a
}
}(jQuery([1]));
Now look at this:
$('a').each(function(i){
$.single(this).append('Anchor number ' + i);
});
Only one jQuery object is being used. You can make it even faster by avoiding the identifier resolution:
$_ = $.single;
$('a').each(function(i){
$_(this).append('Anchor number ' + i);
});
Food for thought. More info here: http://james.padolsey.com/javascript/76-bytes-for-faster-jquery/
this is the native DOM element. $(this) is a jQuery object that allows you to call functions such as .css() on it.
this is typically a DOM object by default, which means it only has the methods on normal DOM objects.
If you want to invoke a library-specific function (such as jQuery's .css function), you have to convert it to a full jQuery object first, which is what $() does by default if you pass it a DOM object.
(You can also pass other things to $(), such as an HTML string (to construct a new jQuery-wrapped DOM object) or a CSS selector (to get a set of jQuery objects that correspond to DOM objects matching the selector).
If you are using Firefox, try console.log($(this)) and console.log(this) to see the difference.
I'm generating an unordered list through javascript (using jQuery). Each listitem must receive its own event listener for the 'click'-event. However, I'm having trouble getting the right callback attached to the right item. A (stripped) code sample might clear things up a bit:
for(class_id in classes) {
callback = function() { this.selectClass(class_id) };
li_item = jQuery('<li></li>')
.click(callback);
}
Actually, more is going on in this iteration, but I didn't think it was very relevant to the question. In any case, what's happening is that the callback function seems to be referenced rather than stored (& copied). End result? When a user clicks any of the list items, it will always execute the action for the last class_id in the classes array, as it uses the function stored in callback at that specific point.
I found dirty workarounds (such as parsing the href attribute in an enclosed a element), but I was wondering whether there is a way to achieve my goals in a 'clean' way. If my approach is horrifying, please say so, as long as you tell me why :-) Thanks!
This is a classic "you need a closure" problem. Here's how it usually plays out.
Iterate over some values
Define/assign a function in that iteration that uses iterated variables
You learn that every function uses only values from the last iteration.
WTF?
Again, when you see this pattern, it should immediately make you think "closure"
Extending your example, here's how you'd put in a closure
for ( class_id in classes )
{
callback = function( cid )
{
return function()
{
$(this).selectClass( cid );
}
}( class_id );
li_item = jQuery('<li></li>').click(callback);
}
However, in this specific instance of jQuery, you shouldn't need a closure - but I have to ask about the nature of your variable classes - is that an object? Because you iterate over with a for-in loop, which suggest object. And for me it begs the question, why aren't you storing this in an array? Because if you were, your code could just be this.
jQuery('<li></li>').click(function()
{
$(this).addClass( classes.join( ' ' ) );
});
Your code:
for(class_id in classes) {
callback = function() { this.selectClass(class_id) };
li_item = jQuery('<li></li>')
.click(callback);
}
This is mostly ok, just one problem. The variable callback is global; so every time you loop, you are overwriting it. Put the var keyword in front of it to scope it locally and you should be fine.
EDIT for comments: It might not be global as you say, but it's outside the scope of the for-loop. So the variable is the same reference each time round the loop. Putting var in the loop scopes it to the loop, making a new reference each time.
This is a better cleaner way of doing what you want.
Add the class_id info onto the element using .data().
Then use .live() to add a click handler to all the new elements, this avoids having x * click functions.
for(class_id in classes) {
li_item = jQuery('<li></li>').data('class_id', class_id).addClass('someClass');
}
//setup click handler on new li's
$('li.someClass').live('click', myFunction )
function myFunction(){
//get class_id
var classId = $(this).data('class_id');
//do something
}
My javascript fu is pretty weak but as I understand it closures reference local variables on the stack (and that stack frame is passed around with the function, again, very sketchy). Your example indeed doesn't work because each function keeps a reference to the same variable. Try instead creating a different function that creates the closure i.e.:
function createClosure(class_id) {
callback = function() { this.selectClass(class_id) };
return callback;
}
and then:
for(class_id in classes) {
callback = createClosure(class_id);
li_item = jQuery('<li></li>').click(callback);
}
It's a bit of a kludge of course, there's probably better ways.
why can't you generate them all and then call something like
$(".li_class").click(function(){ this.whatever() };
EDIT:
If you need to add more classes, just create a string in your loop with all the class names and use that as your selector.
$(".li_class1, .li_class2, etc").click(function(){ this.whatever() };
Or you can attach the class_id to the .data() of those list items.
$("<li />").data("class_id", class_id).click(function(){
alert("This item has class_id "+$(this).data("class_id"));
});
Be careful, though: You're creating the callback function anew for every $("<li />") call. I'm not sure about JavaScript implementation details, but this might be memory expensive.
Instead, you could do
function listItemCallback(){
alert("This item has class_id "+$(this).data("class_id"));
}
$("<li />").data("class_id", class_id).click(listItemCallback);