what defines an object length in javascript? - javascript

function CookieStorage(maxage, path) { // Arguments specify lifetime and scope
// Get an object that holds all cookies
var cookies = (function() { // The getCookies() function shown earlier
var cookies = {}; // The object we will return
var all = document.cookie; // Get all cookies in one big string
if (all === "") // If the property is the empty string
return cookies; // return an empty object
var list = all.split("; "); // Split into individual name=value pairs
for(var i = 0; i < list.length; i++) { // For each cookie
var cookie = list[i];
var p = cookie.indexOf("="); // Find the first = sign
var name = cookie.substring(0,p); // Get cookie name
var value = cookie.substring(p+1); // Get cookie value
value = decodeURIComponent(value); // Decode the value
cookies[name] = value; // Store name and value
}
return cookies;
}());
// Collect the cookie names in an array
var keys = [];
for(var key in cookies) keys.push(key);
// Now define the public properties and methods of the Storage API
// The number of stored cookies
**this.length = keys.length;**
// Return the name of the nth cookie, or null if n is out of range
this.key = function(n) {
if (n < 0 || n >= keys.length) return null;
return keys[n];
};
// Return the value of the named cookie, or null.
this.getItem = function(name) { return cookies[name] || null; };
**// Store a value
this.setItem = function(key, value) {
if (!(key in cookies)) { // If no existing cookie with this name
keys.push(key); // Add key to the array of keys
this.length++; // And increment the length
}**
// Store this name/value pair in the set of cookies.
cookies[key] = value;
// Now actually set the cookie.
// First encode value and create a name=encoded-value string
var cookie = key + "=" + encodeURIComponent(value);
// Add cookie attributes to that string
if (maxage) cookie += "; max-age=" + maxage;
if (path) cookie += "; path=" + path;
// Set the cookie through the magic document.cookie property
document.cookie = cookie;
};
Hello guys, I found this piece of code in a book that I'm reading, and I saw this one line that made no sense to me:
**// Store a value
this.setItem = function(key, value) {
if (!(key in cookies)) { // If no existing cookie with this name
keys.push(key); // Add key to the array of keys
this.length++; // And increment the length
}**
If the object's that we're currently in length property has already been defined by previous line of code (this.length = keys.length;)
Why do we need to increment its length by this.length++ ??
Isn't keys.push(key) enough?
EDIT:
Thanks to all who answered.
After staring at this code for a couple of minutes, i figured out that the first length declaration was relevant only for that "phase" in scripts time.
this.length = keys.length
means that this objects length is equal to the current length of key array.
Later on, when we added another element to key array, it's length increased, this why we must tell it to our object by increasing its own value this time (this.length++;)

It is enough, but if you want to use this function from outside code then you don't have access to the internal values array, so this is a convenience property to get the length.
You can replace it with a getter like this and skip updating it manually each time:
Object.defineProperty(this, "length", {
get: function() {
return keys.length;
}
});
NOTE: As #zzzzBov noted in his comment, IE8 and below don't support getters yet.

this.setItem = function(key, value) {
if (!(key in cookies)) { // If no existing cookie with this name
keys.push(key); // Add key to the array of keys
this.length++; // And increment the length
}
...
};
If you look at just this code, you'll notice that it's declaring a function. The code within this function will execute when setItem is called on the instance of CookieStorage.
The previous line is called when a CookieStorage instance is being created. The purpose of incrementing the length is to produce a public API for the length of the privately stored array.

It is my first answer. Hope it helps.
Looks like this.length does not mean the cookie array's length, isn't it?
Yes, if it uses the push() function, the array's length will definitely increment by one.
You do not have to do it manually.
Unless, this.length mean something else.

For your firtst question:
Basically It's defines the number of the parameters that the function gets only if you Asking for the function Length for example:
CookieStorage.length
function a() {}
function b(a, b) {}
function c(a,b,c) {}
console.log(a.length); //output 0
console.log(b.length); //output 2
console.log(c.length); //output 3
for the this.length question:
Well, this.length is the property that hold the keys.length.
so when you set a new item to the keys array it's update the length property with the new length. so you can use it with:
var cookies = new CookieStorage();
cookies.setItem("test","test");
cookies.length //output 1

Related

Accessing nested JavaScript objects with variables

I want to access (get/set) a nestedJS object with a variable.
For example, static it would look like that:
$obj.children.12.children.32.Name; // Returns "Foo"
Now I have an "Route" array (or whatever is easy too handle):
["children",12,"children",32,"Name"]
And want to get the value of the object.
Like I read here on Stackover, there is an very easy way to do it (Solution 2).
But, now I want to change the value for the passed key/route. Is there any way to do that?
Thank you very much!
Edit:
I can use jQuery/Angluar-Features, if it helps me.
Borrowing code from the accepted answer on the post you've linked to, we can trivially make a getter:
function getFromPath(obj, pathArray) {
var res = obj;
for (var i=0; i<pathArray.length; i++) { res = res[pathArray[i]]; }
return res;
}
We call this with getFromPath($obj, ["children",12,"children",32,"Name"]);.
Since you want to transform this getter function into a setter, you want to set a property on the second-to-last object. We can do this by stopping the loop one iteration early and then performing set with the final property name on the object:
function setToPath(obj, pathArray, valueToSet) {
var res = obj;
// note the `length - 1` here: we don't go to the end of the path
for (var i=0; i<pathArray.length - 1; i++) { res = res[pathArray[i]]; }
// res is now the second-to-last object in the path,
// and we'll set the final value as a property on the object
var finalKey = pathArray[pathArray.length-1];
res[finalKey] = valueToSet;
}
We call this with setToPath($obj, ["children",12,"children",32,"Name"], "Dana");.
Alternatively, if you wanted to do this with just a getter, you could shorten your path by one item and perform the set on the result from the getter:
var secondToLast = getFromPath($obj, ["children",12,"children",32]);
secondToLast["Name"] = "Dana";

Initialize a JavaScript object "tree" to any depth, nested objects

Essentially my I am trying to initialize a JavaScript object and have it contain empty objects with a single key. For example:
getOject('one.two.three')
Would result in the object:
{one:{two:{three:''}}}
As far as I can tell, you can't initialize with dynamic key names unless you use array notation
root[dynamicKey] = 'some variable';
so I need to loop through and based on the number of args initialize each one then assign it's value but the syntax doesn't seem to let me do this in any way that I know of.
So, if it were not a loop it would be like this:
jsonifiedForm[rootKey] = {};
jsonifiedForm[rootKey][childKeys[0]] = {};
jsonifiedForm[rootKey][childKeys[0]][childKeys[1]] = $input.val();
I can't think of a way to do this, I am not typically a JS guy so it might be something simple but I couldn't find anything on Google or Stack Overflow
Thank you in advance!
This function should be what you're looking for.
function getOject(str) {
// this turns the string into an array = 'one.two.three' becomes ['one', 'two', 'three']
var arr = str.split('.');
// this will be our final object
var obj = {};
// this is the current level of the object - in the first iteration we will add the "one" object here
var curobj = obj;
var i = 0;
// we loop until the next-to-last element because we want the last element ("three") to contain an empty string instead of an empty object
while (i < (arr.length-1)) {
// add a new level to the object and set the curobj to the new level
curobj[arr[i]] = {};
curobj = curobj[arr[i++]];
}
// finally, we append the empty string to the final object
curobj[arr[i]] = '';
return obj;
}
Because JavaScript references values in variables instead of copying them "into" variables, we can make our initial value, then make a reference to it which we'll move around as we delve down in:
var getOject = function (k, s) {
// initialize our value for return
var o = {},
// get a reference to that object
r = o,
i;
// we'll allow for a string or an array to be passed as keys,
//and an optional sepeartor which we'll default to `.` if not given
if (typeof k === 'string') {
k = k.split(s || '.');
}
// do we have an array now?
if (k && k.length) {
//iterate it
for (i = 0; i < k.length; i += 1) {
// set a property on the referenced object
r[k[i]] = {};
// point the reference to the new level
r = r[k[i]];
}
}
// send back the object
return o;
}
console.log(getOject('one.two.three'));
console.log(getOject('four|five|six', '|'));
r points to the same thing that o does, initially, and as we move the reference (r) deeper into o and write to it, we're building out o as we go.
The two console.log() calls at the end output the following:
Also notice I let you pass in an array to start with if you feel like it, and made the separator a parameter so that you're not stuck with .

Accessing JavaScript object via key

I have a JavaScript object called data. I am using the following code to sort the keys in the object :
var index = [];
// build the index
for (var x in data) {
index.push(x);
}
// sort the index
index.sort(function (a, b) {
return a == b ? 0 : (a > b ? 1 : -1);
});
I then want to access the value for a particular index key in the following way :
for (var i=0; i<index.length; i++) {
var key = index[i];
document.getElementById(key).value = data.key;
}
However I am getting undefined for the data.key value. Can anyone suggest why ?
Change to
document.getElementById(key).value = data[key];
If the key you want to access is stored within a variable, you have to use the bracket notation. In your code, JavaScript will search for a key named "key" and thus fails.
Example:
var key = 'test';
console.log( data.key ); // yields content of data.key
console.log( data[key] ); // yields content of data.test
How about
Object.keys(data)[key] ?
Not sure it would work, without showing the structure of data.
edit: This way retrieves object key according to numerical index (0,1...,n), and not by name.

Pass string to function to define property name

Good morning
I am wanting to pass a string as a functions parameter in java script but the string will represent the name of a property that i want the function to operate on. I have seen this done before but don't quite comprehend it.
the function below shows what i'm referring to with the "field" parameter. it's passed a value as a string but operates on the property who's name matched the value of the string.
What i want to do is cycle through the array of objects and return only the values stored in the property who's name matches the string passed. The idea is to have one function which can process any objects with properties that have been added to an array and return any property without having to write a loop function for each property.
Below is an example of this type of magic:
listName.sort(sort_by('stringPropertyName', false, function(a){return a.toUpperCase()}));
var sort_by = function(field, reverse, primer){ //http://stackoverflow.com/questions/979256/how-to-sort-an-array-of-javascript-objects
var key = function(x){return primer ? primer(x[field]) : x[field]};
return function (a,b){
var A = key(a), B = key(b);
return ((A < B) ? -1 :(A > B) ? +1 : 0) * [-1,1][+!!reverse];
}
}
If you want to "cycle through the array of objects and return only the values stored in the property who's name matches the string passed", you may do this :
function getValues(array, propname) {
var values = [];
for (var i=0; i<array.length; i++) {
if (typeof array[i][propname] !== 'undefined') {
values.push(array[i][propname])
}
}
return values;
}
The "trick" is to access the property using obj[propname] instead of obj.propname when propname is a variable containing the name of the property.
For example window.location can be accessed as window["location"]
DEMONSTRATION

Remove element from Javascript associative array using array value

I am trying to remove an element from a Javascript associtive array using the value to find it, but I am having trouble. I have tried splice and JQuery's grep method and neither have worked for me. This is what I currently have.
var array_path = new Array();
function bulk_upload(){
var temp_array = new Object();
for (var i = 1; i<8; i++){
temp_array[i] = $('#path' + i).val();
if(temp_array[i]!='' && temp_array[i]!=null){
array_path['path' + i] = $('#path' + i).val();
}
}
process_txt();
}
function process_txt(){
//alert(array_path.indexOf(full_path)); //returns nothing
var removed_element = array_path.splice(getKey(array_path), 1);
//array_path = $.grep(array_path, function(val) { return val != full_path; });
alert(removed_element);//return nothing, just blank alert box
}
function getKey(data) {
for (var prop in data)
return prop;
}
The way to do this is to use the delete operator.
delete array_path[getKey(array_path)]
Some Background Information
In JavaScript, almost everything descends from Object.prototype. JavaScript, being an open and dynamic language allows you to create/modify properties of objects by simple assignment. This is very similar to what an associative array -- a structure that contains keyed values.
Under the hood an array is just an object that descends from Array.prototype with numeric keys and a special property called length. The length property just returns one greater than the highest numeric property. In essence, an Array is an object with different semantics.
If you're wanting an associative array then Array is not the object you want to descend from. You would want to descend directly from Object. There are two ways to do that, you could either use the new operator or an empty object literal. The syntax for both is below:
var o = new Object();
var o = {};
The second is preferred since it's a little bit more concise.
I wrote a blog post about this a while back, have a look if you want a little bit more info.
There is no such thing in JavaScript as an "associative array" per se. The data structure which corresponds to this concept is simply a JavaScript Object.
Of course, a JavaScript Array (like essentially everything in JavaScript) is an Object, but one with additional capabilities. So you can use an Array as a key-value map, but it's really not the correct structure for that.
To remove a key from an Object, you just do something like this:
var myObj = {};
var myKey = "blah";
myObj[myKey] = 1234; // Adds or updates value for "blah" to 1234.
delete myObj[myKey]; // Removes key-value pair for "blah".
Have you tried delete hash.someKey; ?
You can give your object a remove method, or use apply or call to use another object's remove method, if defined.
function myObj(members){
for(var p in members) this[p]= members[p];
}
myObj.prototype.remove= function(val){
for(var p in this){
if(this[p]=== val) delete this[p];
}
return this;
}
myObj.prototype.toString= function(){
var A= [];;
for(var p in this){
if(this.hasOwnProperty(p)){
A.push(p+':'+this[p])
}
}
return '{'+A.join(', ')+'}';
}
var O= new myObj({a: 1, b: 10, c: 100});
alert(O)
O.remove(10);
alert(O)
I'm not psychic, so I can only guess that you wanted to accomplish something like this:
var paths = [];
function getPaths() {
for(var i = 1; i < 8; ++i) {
var value = $('#path' + i).val();
if(value) paths.push(value);
}
}
function process() {
var firstPath = paths.shift();
// do stuff
}
getPaths();
if(paths.length) process();

Categories