How to call a object method without object instance? - javascript

I have a method loadSet which creates elements with datas from the localstorage, and this should be run on page load i am calling it via
ReminderSet.prototype.loadSet(); // works fine
My question is, is there any other way to call a method that don't need a reference to an object instance? like person1.loadSet(); or should i abandon this and make it as a regular function?
ReminderSet.prototype.loadSet = function() {
var keys = Object.keys(localStorage),
i = 0,
key,
array;
for (; key = keys[i]; i++) {
const setId = localStorage.getItem(key);
array = JSON.parse(setId); //parse and store key values
let array_index = 0;
//Re-create the reminders and set their properties//
$reminderSection.append($('<div/>').addClass('set').attr('id', key) //Set the ID
.append($('<div/>').addClass('set-title').append($('<h1>').attr('contenteditable', 'true').text(array[array_index].set_title)), //Index is always at 0//
$('<div/>').addClass('create-reminder-control').append($('<button>').addClass('add-new-reminder').text("+ add new"), $('<input>').addClass('create-reminder-value').attr({ type: "text", placeholder: "get something done" })), $('<div/>').addClass('reminder-lists'), $('<div/>').addClass('save-control').append($('<button>').addClass('save-reminder-button').text('Save'))))
//Get our key values //
for (; array_index < array.length; array_index++) {
/*Select the element id */
$("#" + key).children('.reminder-lists').append($('<div/>').addClass('a-reminder').attr('contenteditable', 'true').text(array[array_index].description).append($('<div/>').addClass('delete-reminder').text('x'))) //Get the reminders
} //end
}
};

If loadSet doesn't need or use an instance, it doesn't make any sense for it to be on ReminderSet.prototype. Either make it a standalone function:
function loadSet() {
// ...
}
// Call it like so: loadSet();
...or a property on ReminderSet itself:
ReminderSet.loadSet = function() {
// ...
};
// Call it like so: ReminderSet.loadSet();
Only put functions on the object that a constructor's prototype property refers to if they need to use this (the instance).

You can set the function directly as a property of the other ReminderSet:
ReminderSet.loadSet = function() {//etc.}
Then you can simply call: ReminderSet.loadSet()

Related

Why Javascript object didn't change?

Can someone explain me this strange js behavior ?
All of this is in AngularJS.
I have helper function in my main app.js to simply return element from an array by its id:
var MyLib = MyLib || {};
MyLib.helpers = {
find: function(needle, stack) {
for (var i = 0; i < stack.length; i++) {
if(stack[i]._id === needle)
return stack[i];
}
return false;
}
}
Then I have factory and function to handle database change:
// categories are grabbed from db
var categories = [some array of objects];
// change is object returned from database that has all info about object as well as new object itself
function handleChange(change) {
var _category = MyLib.helpers.find(change.id, categories);
// if deleted, that part is ok
if(change.deleted) {
var idx = categories.indexOf(_category);
if(idx !== -1) {
categories.splice(idx, 1);
}
} else {
// if updated that part is weird
if(_category) {
_category = change.doc;
}
// if newly added that part is ok
else {
categories.push( angular.copy(change.doc) );
}
}
}
Why when I try to update element grabbed from categories array doesn't update in categories array ?
// categories ARE NOT updated after this
_category = change.doc;
and only when I refer to categories by index like this:
// categories ARE updated after this although _category is returned from this array by index (find function)
var idx = categories.indexOf(_category);
categories[idx] = change.doc;
I don't understand this...
You are overwriting the variable with a new value and any reference to prior value is gone.
Instead of overwriting the original object value with a new object you could update the existing object using angular.extend()
angular.extend(_category, change.doc);
I didn't analyze everything, but you should always have dot notation.
_category pass by value, and will not change when 'MyLib.hel ...' is changed
var _category = MyLib.helpers.find(change.id, categories);
something.category pass by reference, and will be changed when 'MyLib.hel ...' is changed
var something.category = MyLib.helpers.find(change.id, categories);

scope of "this" changes when using grep in jquery widget

I have two groups of JSON data, one containing the data I want to filter down, and a second group representing the criteria for the filter.
The filter structure is pretty basic. It contains an Id of the element it's filtering on and it's value.
The other structure contains multiple fields, including the Id that relates back to the filter structure.
Both of these are stored in the global part of the widget. Normally, I would use this.filterData or this.jsonObjects to access them. However, if I try to filter using either grep, or the javascript array.filter function, then "this" changes, so I can't access the data anymore. Is there a way around this?
applyFilters: function() {
//var returnedData = $.grep(this.options.jsonObjects, this.grepFunction);
var returnedData = this.options.jsonObjects.filter(this.filterMatch);
filteredData = returnedData;
this.options.onFilterApply.call(this);
},
filterMatch: function(element) {
for(var key in this.filterData) {
if(this.filterData.hasOwnProperty(key)) {
for(var a = 0; a < this.filterData[key].values.length; a++) {
if(element[this.filterData[key].id]==this.filterData[key].values[a]) {
return true;
}
}
}
}
return false;
}
Hope this makes sense. During the applyFilters function, "this" represents the widget itself and it works fine. But as soon as it enters the filterMatch function, "this" becomes the window, so this.filterData is undefined. How can I access the filterData inside that function, or ultimately, what is the best way of filtering down a list of JSON objects?
You can save your scope in a variable before entering the filterMatch function.
Something like :
var that = this;
applyFilters: function() {
//var returnedData = $.grep(this.options.jsonObjects, this.grepFunction);
var returnedData = this.options.jsonObjects.filter(this.filterMatch);
filteredData = returnedData;
this.options.onFilterApply.call(this);
},
filterMatch: function(element) {
for(var key in that.filterData) {
if(that.filterData.hasOwnProperty(key)) {
for(var a = 0; a < that.filterData[key].values.length; a++) {
if(element[that.filterData[key].id]==that.filterData[key].values[a]) {
return true;
}
}
}
}
return false;
}
You can bind your this to the function scope also.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

How to get reference to function in array if you know only the name of function?

lets say I have array of functions such as [ function f1{}, function f2{}] and I know that the function I want to get a reference too is called "f2", so that I can remove it from the array, how would I go about it? I tried using the object that contains an array like
ctrl.$parsers["f2"] but it does not return anything. Is this possible?
You could iterate over the array and inspect the function's name attribute:
function getNamedFunction(arr, name) {
for (var i = 0, l = arr.length; i < l; i++) {
if (arr[i].name === name) {
return arr[i];
}
}
}
But Function#name is not a standard property:
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.
A better (more compatible) approach would be to store your functions in an object:
var functions = {
'f1': f1,
'f2': f2,
};
and access it with
functions['f1']
You could use the filter method of the Array to select functions with a specific name
var myFunctions = [
function a(){ alert(1); },
function b(){ alert(2); },
function c(){ alert(3); }
];
var someName = 'c'; // name of function to search for
// filter array checking the name property of each function in the array
var someFunction = myFunctions.filter(function(f){
return f.name == someName;
})[0]; // get the first function from the resulting filtered array
someFunction(); // alerts '3'
Use the name prop and try this
for (var i=0;i<arr.length;i++)
{
if (arr[i].name=='f2')....
}
Later you can use splice to remove the element.
array.splice(index, 1); ( returns the same array instance)
p.s.
This feature is non-standard
So what can you do ?
you can do this :
var g=[function f2(){},function f4(){}];
for (var i=0;i<g.length;i++)
{
var m=g[i].toString().match(/function\s+(\w+)/i);
if (m && m[1]=='f4') alert(i);
}

store value in JSON on button click

I am new in JSON, i am trying to save data using JSON. I have a list of element with some button when we click the button i want the corresponding value of button are save in JSON. I am also want to compare the title with already exists in JSON.
Demo Here
You can simply use a for loop to check if the element with that title is already there:
function alreadyAdded(itemTitle) {
for (var i = 0; i < objArray.length; i++) {
if (objArray[i].title === itemTitle) {
return true;
}
}
return false;
};
Also, you are not using a json object, just a JavaScript array.
Demo
try this
http://jsfiddle.net/Z3v4g/
var counter = 0;
var jsonObj = []; //declare object
$('.imgbtn').click(function () {
var title = $(this).parent().parent().find('span').html();
var image = $(this).parent().parent().find('img').prop('src');
for( var i=0; i<jsonObj.length; i++){
if( jsonObj[i].title == title ) return false;
};
counter++;
$('#lblCart').html(counter);
jsonObj.push({
id: counter,
title: title,
image: image,
description: 'Example'
});
});
I am assuming you want to store values in an array, and during a button click you want to check if the item already exists in the array. If this is true, then you can use the following code -
var counter = 0;
var jsonObj = []; //declare object
$('.imgbtn').click(function () {
var title = $(this).parent().parent().find('span').html();
var image = $(this).parent().parent().find('img').prop('src');
var match = $.grep(jsonObj, function (e) {
return e.title == title;
});
if (match.length > 0) {
// This title already exists in the object.
// Do whatever you want. I am simply returning.
return;
}
counter++;
$('#lblCart').html(counter);
jsonObj.push({
id: counter,
title: title,
image: image,
description: 'Example'
});
});
Notice that I have declared the array outside the callback function. This ensures that all the invocation of the callback operate on the same array object. Declaring it inside the callback was only making it available for a single callback invocation.
Also note that you are simply using an array to store plain JavaScript Objects.
Demo.
First:
var jsonObj = []; //declare object
This is not a JSON. This is an Array. JSON is just the notation of Javascript Object. To declare a object you should do:
var jsonObj = {};
or:
var jsonObj = new Object();
After this, you can approach what you asked doing this:
var counter = 0;
var jsonObj = new Object();
$('.imgbtn').click(function () {
var title = $(this).parent().parent().find('span').html();
var image = $(this).parent().parent().find('img').prop('src');
if (!(title in jsonObj)) { // if item is not in the object, (title in jsonObj) returns true of false
jsonObj[title] = { // When you have hundreds of items, this approach is way faster then using FOR loop, and if you need to alter the item or get one value, you can just call it by name: jsonObj['ABC'].image will return the path of the image
id: counter,
image: image,
description: 'Example'
}
counter++;
$('#lblCart').html(counter);
} else {
// Do what you want if the item is already in the list
alert('Item already in the list');
console.log(jsonObj[title]);
}
});
DON'T use FOR loops to do what you wan't, it will just slow down your application if the counter gets high.

Returning a private variable in JavaScript

I don't know why console.log(Set.current_index) shows 0 instead of 3.
var Set = (function() {
var set = [];
var index = 0;
function contains(set, e) {
for (var i = 0; i < set.length; i++) {
if (set[i] === e) {
return true;
}
}
return false;
}
var add = function(e) {
if (!contains(set, e)) {
set[index++] = e;
}
}
var show = function() {
for (var i = 0; i < set.length; i++) {
console.log(set[i]);
}
}
return {
add: add,
show: show,
current_index: index
};
})();​
Set.add(20);
Set.add(30);
Set.add(40);
Set.show();
console.log(Set.current_index);
As written current_index just gets the initial value of index - it doesn't mirror any changes to that value because that variable is of primitive type.
If you have a 'reference type' (i.e. an object or array) then changes to its contents become visible in any other variable that references the same object. That doesn't happen with primitive types, they're copied "by value" into the new variables, and changes to the original variable don't affect the copy.
You need to make current_index into a function that returns the current value of index, or write it as a getter which allows you to treat .index as a read-only property by invisibly calling a function to return the current value.
For an example of the latter method (which requires ES5, or shims to replicate the functionality) see http://jsfiddle.net/alnitak/WAwUg/, which replaces your current return block with this:
var interface = {
add: add,
show: show
};
Object.defineProperty(interface, 'index', {
get: function() {
return index;
},
enumerable: true
});
return interface;
Javascript always passes by value except when a variable refers to an object. So your initialization of current_index just gets the initial value of index rather than permanently pointing to the variable, so after that initialization, the two variables are on their separate ways therefore incrementing index doesn't increment current_index.

Categories

Resources