Correct me if I'm wrong. I'm not sure if shorthand is the correct word. But, it's the closest I can come up with:
For example:
this.getAttribute
I am using this a lot throughout one of my scripts, over 20 items.
Is it possible to just reference it like:
getA
or something? Instead of typing this.getAttribute over and over again? I know it seems likes a first world problem, but I am very OCD about my code and like to be minimal but still sustain readability. getA to reference this.getAttribute still makes a alot of sense (to me anyway), and in essence, shorter code. Any way to accomplish this?
if you call assign a method of an object to a var and call it by that, it the value of this inside the method will be the global context, as the function context is bound to where it got called from, so you can't do that.
However, you can use the built in Function method bind to preserve the context, but it's a rather expensive operation just to alias your method.
var getA = this.getAttribute.bind(this);
getA("yourAttribute");
or use call to enforce the context when you call it
var getA = this.getAttribute;
getA.call(this,"yourAttribute");
but both are not really great and in most cases all you need to do is to keep the actual return value in a var and reuse that, without invoking the getter at all. The getter is verbose because that's a good way to make an expensive method look expensive, and discourage people from calling it 20 times in a row in the first place. They usually should only be called when you expect a different result.
var a = this.getAttribute("yourAttribute");
When you say you call it 20 times in 20 different places I'm relatively sure those are not 20 places that expect the value to be different, especially when they are inside the same function scope.
If you are dealing with custom data-* attributes you can also just directly retrieve it from the .data property on your element, it's a map of all your data-attributes which is the ideal scenario.
<element data-your-attribute="yourData"></element>
var a = this.data.yourAttribute; //automatically updated and name converted from dash to camelCase
(all examples assume this refers to you element, and your function is a method of your element)
Yes, you can create a function like this:
function getA(element, attr) {
return element.getAttribute(attr);
}
And then, instead of this.getAttribute(attr), use getA(this, attr).
However, if you want to use it to get several attributes of the same element, and you want to avoid avoid passing this each time, you can use
var getA = this.getAttribute.bind(this);
And then, instead of this.getAttribute(attr), use getA(attr).
To sum it up:
#Adeneo says:
function getA(element, attr)
{
return element.getAttribute(attr);
}
I said:
Element.prototype.getA = Element.prototype.getAttribute
Which can be used as:
var attr = getA(document.getElementById("test"), "attr"); //Adeneo
var attr = document.getElementById("test").getA("attr"); //Mouser
I strongly advise against extending the Element object.
jQuery does the following:
They have their master function object $. That function has a method called attr. So the master function object finds an element on the page to which you can call the method attr.
$("element").attr("attr");
To reproduce:
var masterFunction = function(selector)
{
this.result = document.querySelectorAll(selector);
}
var selectElement = function(selector)
{
return new masterFunction(selector);
}
masterFunction.prototype.attr = function(attr)
{
var returnArray = [];
Array.prototype.forEach.call(this.result, function(element){
if (element.hasAttribute(attr))
{
returnArray.push(element.getAttribute(attr))
}
});
return returnArray;
}
Please remember that this, like jQuery returns an array containing the results.
Related
Let's say that I'm making a JS library that has some functions for DOM manipulation. I have a few functions that are added to elements, for example myElement.empty();. I would like the same functionality for NodeLists (the objects returned from, for example, querySelectorAll). To dynamically add the functions, I have done the below (and please note that the below does work):
var funcs=["text","html","attr","remove","empty","css"];
var n=funcs.length;
while(~--n){
var f=function(){
var i,l=this.length;
for(i=0;i<l;i++){
this[i][ funcs[arguments.callee.n] ].apply(this[i], arguments);
}
return this;
};
f.n=n;
NodeList.prototype[funcs[n]]=f;
}
This works, but I have heard that arguments.callee doesn't work in "strict" mode.
Someone said to give the function a name, but I can't, although I tried:
var funcs=["text","html","attr","remove","empty","css"];
var n=funcs.length;
while(~--n){
this[funcs[n]]=function(){
var i,l=this.length;
for(i=0;i<l;i++){
this[i][ funcs[name] ].apply(this[i], arguments);
// In the above it has 'name' which references the function name
}
return this;
};
NodeList.prototype[funcs[n]]=this[funcs[n]];
}
That didn't work. I was able to do it using eval. I decided not to use eval, although it worked (by putting n into the string and making the function out of that). I figured that arguments.callee is probably better than eval, if I had to use one of them.
How can I make my function work without using anything that is suggested against (such as arguments.callee and eval)?
Edit for more details:
Let's say I define an empty function (and once again for the purpose of the question let's assume that modifying the prototype is OK):
Element.prototype.empty=function(){
while(this.childNodes[0])
this.childNodes[0].remove();
};
This works for one element. What if the user wants to do something similar to:
document.querySelectorAll("button .myclass").empty();
So I want to make a script that dynamically creates functions for NodeLists that call the corresponding functions for each element, for example:
NodeList.prototype.empty=function(){
var i,l=this.length;
for(i=0;i<l;i++)
this[i].empty();
return this;
};
If I want to do the above I will need to create many functions that do very similar things. So I want to write some code that dynamically creates functions for NodeList. As you probably read above, I did it with arguments.callee (and eval), but I want to use something that is standard and considered OK to use.
How would I do this?
If you need any more information then please ask in the comments, and I will try to respond as soon as possible.
Don't use that weird iteration style, but an idiomatic for … of loop that allows for a block-scoped variable:
const funcNames = ["text","html","attr","remove","empty","css"];
for (const name of funcNames) {
NodeList.prototype[name] = function(...args) {
for (let i=0; i<this.length; i++) {
this[i][name](...args);
}
return this;
};
}
No reason to access the current function or store the name on its .n property, just access it through closure.
I'm writing a framework that uses wrapping of functions in order to create a debug tool. Currently, I want to report and aggregate information upon function call. I'm using the following code:
function wrap(label, cb) {
return function () {
report(label);
cb.apply(this, arguments);
}
}
And then in order to bind the debug operation I will use:
function funcToWrap (){/* Some existing function*/}
funcToWrap = wrap("ContextLabel", funcToWrap);
Now, when funcToWrap is invoked, it is wired to go through report() method.
The requirement I have is to now change this syntax so that the wrapping is done via:
funcToWrap.wrap("ContextLabel");
Ideally, something like this would solve my issue, but this of course is illegal:
Function.prototype.time = function(label){
var func = this;
// The actual difference:
this = function () { // ILLEGAL
report(label);
func.apply(this, arguments);
}
};
Thank you from ahead for any insight regarding this.
The requirement I have is to now change this syntax so that the wrapping is done via:
funcToWrap.wrap("ContextLabel");
Unless there's a funcToWrap = at the beginning of that, you simply can't meet that requirement. There's no way to change the guts of the function, you can only do what you're doing, create a new function to take its place.
If you have a funcToWrap = at the beginning, of course, it's quite straightforward. But I take it that's not the requirement.
But if I'm mistaking the requirement, then:
Function.prototype.wrap = function wrap(label) {
var f = this;
return function () {
report(label);
return f.apply(this, arguments); // Note the added `return` here
};
};
Usage:
funcToWrap = funcToWrap.wrap("ContextLabel");
Reasonably certain from the question, though, that A) That's not what you're looking for, and B) You could have done it if it were.
The requirement I have is to now change this syntax so that the wrapping is done via:
funcToWrap.wrap("ContextLabel");
That's impossible. One cannot alter a function's behaviour from the outside, it's much like an immutable primitive value in that regard. The only thing you can do is to create a new function and overwrite the old one, but this overwriting has to be explicit. You could use some eval magic for that (like here), but I recommend to use an assignment like in your first example (regardless whether the wrap function is static or a Function method).
I'm curious from both a performance and a "best practices" standpoint. I'm using a lot of jQuery in my JavaScript, and often find myself passing jQuery objects as arguments into functions I'm writing. Is it more efficient/effective to pass the selector string rather than the actual jQuery object as the argument? Is this just a stylistic difference, or are there any good reasons to use one method over the other?
Using jQuery objects in arguments:
function updateSelectOptions(optionsData, $selectElement) {
// function code
}
Or using a selector string as the argument:
function updateSelectOptions(optionsData, selectorString) {
var $selectElement = $(selectorString);
// function code
}
You should accept anything the jQuery constructor can for maximum flexibility.
Re-wrapping a jQuery collection doesn't blow up, so I often use something like...
var fn = function(elems) {
var $elems = $(elems);
};
That way, you can accept a jQuery collection, selector string or reference to native DOM element(s).
If you find yourself wanting to write a function that takes a jQuery object as a parameter, why not just make your function a jQuery plugin? It's pretty easy, and it makes using the function fit in with the rest of your jQuery code.
Instead of
function something(jq) {
jq.css("color", "red");
});
you'd write
$.fn.something = function something() {
this.each(function() {
$(this).css("color", "red");
});
return this;
};
Now when you want to turn something red, you can just say
$(".whatever").something();
The value of this in a jQuery plugin is the jQuery object that's being passed along the chain. You don't have to wrap it with $(this). Unless your function is something that returns some value, it's good to return whatever's passed in so that you can use your own plugin in the middle of a dotted chain.
In my opinion, passing the object is fine and would be better for performance.
Why?
Most of the time, the reason for using functions is to reuse code. Hence, if you pass the string (the selector) such as updateSelectOptions(optionsData, selectorString)
every time you call the function and then use that string to select the element:
var $selectElement = $(selectorString);
This will consume more memory, because the element will have to be searched for every function call.
Where if you pass the cached object this element will only be selected and searched for only once.
The second approach remove any reference to the object after the function finished to execute. The first one allow you to keep the reference to the object to manipulate it outside the scope of the function.
I'm reading the source from mongoose
Collection.prototype.onOpen = function () {
var self = this;
this.buffer = false;
self.doQueue();
};
I don't understand why the author assigns this to self and runs self.doQueue(). Why not just run:
this.buffer = false;
this.doQueue();
I'm new to javascript, thanks for help.
You're right, in this instance they could have simply used this.
The use of me or self is a bit of a hack to ensure the correct context of this is used, as within JavaScript the scope of this is variant. If for example you have an event trigger a function within your class, this would be different, and wouldn't be your object that houses the function, but instead the object that called the function. To resolve this people often use me or self to ensure they're referring to the correct object... this, as in the actual object.
Just to give more clarity to #richard said earlier,
Collection.prototype.onOpen = function () {
var self = this;
this.buffer = false;
this.onclick = function(){
//do some other operations here
//if you refer `this` here then, `this` will refer to present function not the above. so to make sure it is referring to exact object people pass this to `me` or `self`
self.doQueue();
}
};
The only reason you would usually do that is if the call to doQueue() is inside a block that will change the value of this such as another function.
In this case however it doesn't serve any purpose and was probably a remnant of older code that was not changed back.
Most likely the developer wanted consistency, but failed at doing so.
Otherwise you'd be using this in some functions, self in other functions and a mix of both in other functions, depending on where you use the object and if you use nested functions/callbacks.
By always assigning this to self and then using the latter you have one additional assignment at the very beginning of each function but you always use self to access the object.
However, what the developer did in the code you posted does not make much sense. He should either use self or this both times instead of a mix that is not even necessary.
self is a copy of 'this',but it always refer to the right object,and 'this' may not.
I'm working on implementing a Javascript model on a web app that I'm working on. The purpose of the model is to simply hold information about the state of the page. I have come across two different implementations for creating the model and I was wondering which one was the best to use. The first implementation:
var PageInfo = function () {
this._info = {};
};
PageInfo.prototype = {
getInfo: function () {
return this._info;
},
setInfo: function (updatedInfo) {
this._info = updatedInfo;
}
};
The 2nd implementation:
var pageInfo = function () {
var info = {};
return {
getInfo: function () {
return info;
},
setInfo: function (updatedInfo) {
info = updatedInfo;
}
}
};
Another question I have is about the setInfo() function. When I find myself updating the model, I often want to have the info that I just changed immediately available to me. This has led me to write the setter function as such:
setInfo: function(updatedInfo) {
info = updatedInfo;
return info;
}
which I implement in the code like so:
var info = pageInfo.setInfo(newInfo);
Is this ok or should I be implementing it like this?:
pageInfo.setInfo(newInfo);
var info = pageInfo.getInfo();
Just trying to follow best practices and avoid any issues that may come up from using the wrong implementation.
Both implementations are perfectly acceptable. The former will be faster, albeit by a negligible amount, but exposes its internals to the world. This means that any variable that holds a reference to an instance of PageInfo will be able to manipulate the _info property. Generally this is a non-issue as properties that being with an underscore (_) are considered to be private and should be left alone.
The latter implementation makes use of a concept called closure. A closure is formed when a value is returned that maintains a reference to its defining scope. Essentially it means that the info variable is kept alive. Since the variable is "closed over" it's impossible for it to be modified outside of the interface methods that you provide. In my experience this is rarely needed.
In regards to your second question, again either is acceptable. I like the interface for accessor methods to be consistent so I would say that setInfo should not return anything but there are exceptions to every rule. The exception to the rule occurs when the the value returned by getInfo will not be congruent with what was passed to setInfo. That is, if getInfo returns different value than the value passed to setInfo you might want to return the value out of setValue. Otherwise, the caller could simply re-use the value that was passed to setValue instead of calling getValue.
1st implementation is better, as in 2nd implementation every time you call pageInfo function, you are defining 2 new functions (or set up a closure), while 1st implementation is defining them in prototype and reusing.
For other question, if you only do this to preserve lines, i might suggest something like:
var info = pageInfo.setInfo(newInfo) || pageInfo.getInfo();
assuming setInfo returns undefined.