I am reading some values in data attribute fields. I have seen two easy ways to read the data as shown below:
var webappData = document.getElementById('web-app-data'),
rating = webappData.dataset.rating;
OR
var effectData = $('.effects-list li'),
creative = effectData.filter('[data-creative]').data("creative");
My question is which of these has better performance or do they really differ?
I have a page with many data attributes that I am accessing and I would like to use the method that has the best performance.
Any guidance on understanding the difference between the two would be appreciated. While I am looking at performance specifically if there are other reasons to use one over the other I would like to know this as well.
dataset is a native property of an element that contains the data attributes, it's a new(ish) addition and as such is only supported in IE11+, Chrome 8+, FF 6+ etc.
A more cross browser solution would be to get the attribute directly
webappData.getAttribute('data-rating');
data() is a jQuery method, and other than using the HTML5 data attribute to set the inital value if none exists internally, it has nothing in common with dataset.
data() stores whatever data you pass it in an internal object created by jQuery, so this for instance would fail
$(element).data('key', 'value');
element.dataset.key // undefined
as the data is not stored in the attributes at all, but internally by jQuery.
The jQuery equivalent of getting and setting the data attribute would be attr()
$(element).attr('data-key', 'value');
The native methods are probably faster, but as they are not really comparable to jQuery's data() it doesn't really matter, but for getting the data attribute I would think the fastest method with the best browser support would be
var rating = webappData.getAttribute('data-rating');
Related
I have this scenario where i need to assign a java-script object to div attribute.
var temp["name"]="first";
i assigned it to a div tag attribute using Jquery.
div.attr('data-polygon',temp);
Object [ <div#image01> ]
when i try to retrieve it , it does not come back same.. it is converted as String.
div.attr('data-polygon');
"[object Object]"
Any proper option / alternate to retain the object in attribute? please let me know
Attributes are always strings.
Here are two options for doing this; since you're already using jQuery, the first is probably best:
jQuery's data
jQuery provides the data method for doing this:
// Setting -- notice no "data-" prefix
div.data("polygon", temp);
// Retrieving
varName = div.data("polygon");
Under the covers, traditionally data assigns the element a unique ID and manages a data cache for the element, separate from it. I think in the v3 branch they've updated it to actually store the data on the element (there were memory issues with doing that in Internet Explorer 8 and earlier, which is why jQuery didn't do it before).
Assign it as your own "expando" property
If you don't need to support Internet Explorer 8, you can just create a property on the actual DOM element.
// Setting
rawDiv.myUniquePrefixToAvoidConflicts_polygon = temp;
// Getting
varName = rawDiv.myUniquePrefixToAvoidConflicts_polygon;
Note that to avoid conflicts with the many predefined properties elements have, and future ones they don't have yet, you'll want to use a likely-unique prefix.
As the title says, I am looking for the fastest way to wrap a native C++ object into a v8::Object. A sample of the code I currently have looks like:
Nan::Persistent<v8::Function> Vector3::constructor;
void Vector3::Initialise() // Static, Called once.
{
v8::Local<v8::FunctionTemplate> objectTemplate = Nan::New<v8::FunctionTemplate>();
objectTemplate->SetClassName(Nan::New("Vector3").ToLocalChecked());
objectTemplate->InstanceTemplate()->SetInternalFieldCount(1);
constructor.Reset(objectTemplate->GetFunction());
}
v8::Local<v8::Object> Vector3::WrapObject(double* components) // Static
{
v8::Local<v8::Function> constructorFunction = Nan::New(Vector3::constructor);
v8::Local<v8::Object> localObject = Nan::NewInstance(constructorFunction).ToLocalChecked();
Nan::Set(localObject, Nan::New("X").ToLocalChecked(), Nan::New<v8::Number>(components[0]));
Nan::Set(localObject, Nan::New("Y").ToLocalChecked(), Nan::New<v8::Number>(components[1]));
Nan::Set(localObject, Nan::New("Z").ToLocalChecked(), Nan::New<v8::Number>(components[2]));
return localObject;
}
The full code is a bit more complex as each vector is a property of some wrapped entity class.
From reading the many online tutorials and posts it seems like this is one of the most common ways to wrap an object, however, is there any faster way?
Profiling the code highlights Nan::Set as a major bottleneck. In particular, it seems Set internally calls two v8 methods:
v8::internal::Object::SetProperty
and
v8::internal::LookupIterator::PropertyOrElement
with each method taking up about 50% of the total Set function.
So my thoughts are:
Is there anyway to bypass the lookup function and call SetProperty directly?
Surely the lookup step is redundant here as I know ahead of time that I am setting a property and not an element.
Is there perhaps a way to define the properties on the object template in the Initialise method and then just set them using some integer index (while still retaining them as named properties and not elements) rather than the string name so the lookup is faster?
Is there any way to set multiple properties on an object at the same time?
Is there a better method entirely?
This w3schools page mentions the HTML DOM createElement() Method. For example, you can create a button by
var btn = document.createElement("BUTTON");
Now, I want to attach some information to this button. What is the appropriate way to do it? If I want to attach the array ["one", "two", "three"], can I just do
btn.myOwnInformation = ["one", "two", "three"]
?
You can use the html5 data attribute to add arbitrary data to DOM elements.
btn.setAttribute('data-array','one,two,three');
Get the data back by using split;
Here's an example: jsFiddle
That certainly works if you try, but it is usually discouraged, for a few reasons:
Separation of concerns
The DOM is meant for display structure and logic, so any other kind of data is better stored separately.
Collision with future DOM specifications
What if you choose a property or method name that becomes a standard in the future? Your code may become buggy on future browsers.
Browser compatibility
Old browsers (IE 6/7) could leak memory when data was attached to DOM objects. It's less of a problem now, but since JavaScript objects provided by browsers ("host objects") are less controllable, I suggest avoiding to extend them (or their prototypes) unless you know what you're doing.
For those reasons, libraries like jQuery use a separate structure to store arbitrary data (and also event handlers) and relate them to DOM elements. For the same reasons, jQuery wraps selected DOM nodes in jQuery objects, instead of directly extending the DOM interface with methods like append, css, etc.
Related questions and references
Storing data in the DOM
Javascript DOM: Setting custom DOM element properties
What’s wrong with extending the DOM
Can I just make up attributes on my HTML tags?
Jquery data() storage
Storing custom data in dom elements
I know its bad to store data in the DOM, but why?
If you are willing to use jQuery
there's a function which can match you requirement
jQuery.data()
code can be written like this:
var $btn = $('<input type="button" value="buttonName">');
$btn.data('keyName',["one", "two", "three"]); //insert data
var getData = $btn.data('keyName'); //get data by keyName
(Sorry, I don't have enough reputation to use commend)
I have a use case which requires getting multiple html5 data-attributes from elements. This occurs within a loop across many elements and pushes the data in to an array for caching.
From doing some research it appears that using el.getAttribute('data-whatever') is faster than using the native html5 dataset method however I need to get around 5 separate data attributes from the same element.
The dataset method allows you to retrieve all data-attributes with one call and then access them with standard object dot notation ( dataset.index, dataset.whatever, dataset.somethingelse ) whereas using getAttribute I have to make repeated getAttribute calls to retrieve all the needed data.
If using non compliant attributes I can of course simply use dot notation to access the properties speeding up this function considerably. But using html5 data attributes this does not work (i.e. el.data-whatever will always be undefined).
I wish to remain compliant to standards therefore I am looking for the fastest possible way of retrieving these multiple data attributes.
Thanks in advance.
I made this test:
http://jsperf.com/dataset-vs-getattribute-2
The test is a the following:
dataset all:
var data = el.dataset;
getAttribute all:
var data = {
id: el.getAttribute('data-id'),
user: el.getAttribute('data-user'),
dateOfBirth: el.getAttribute('data-date-of-birth')
};
dataset single:
var user = el.dataset.user;
getAttribute single:
var user = el.getAttribute('user');
https://developer.mozilla.org/en-US/docs/Web/API/element.dataset
Just benchmark it :
http://jsperf.com/dataset-access-vs-getattrb
It still looks to be 2 times faster using getAttribute on chrome.
I'm using a noop to prevent the JIT from optimizing it away.
I'm writing a jQuery plugin that works on a piece of JSON data object.
This data needs to be calculated by the plugin only once, so I want to calculate it on the first call to the plugin and store it to be used in every subsequent call.
My questtion is whether there's a standard and accepted methodology for storing data used by jQuery plugins.
Assuming my plugin is:
jQuery.fn.myPlugin = function(){...}
I was thinking of storing it's calculated data in:
jQuery.myPlugin.data = {...}
Is this the acceptable way of going about it?
I think storing it there is acceptable (or jQuery.fn.myPlugin.data for that matter)...or instead use your own ID in $.cache which is for storage but uses integer IDs for jQuery events and data, so you won't have any conflict, for example:
$.cache["myPlugin"] = myData;
//and to get:
var dataToUse = $.cache["myPlugin"];
The main reason I'd take this route is it eliminates the potential jQuery.something naming conflicts that could arise with future versions.