How to convert object literal to function - javascript-objects

Is there any dynamic way to convert/clone this object:
var object = {
a: 2,
b: function(){
return this.a;
}
}
Into this kind of function object:
function object(){};
object.a = 2;
object.b = function(){
return this.a;
};
Is this possible? how can I do so dynamically?

You can just copy everything, though I would use the prototype:
function toClass(obj) {
var func = function () {};
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
func.prototype[i] = obj[i];
}
}
return func;
}
A whole other question is how useful this actually is and whether there is a better solution to the underlying problem.
Fiddle: http://jsfiddle.net/pb8mv/

It is a little bit strange that you need such a thing. If I have to guess, I think that you have an object and you want to extend it. I.e. you want to create function based on that object, so you later create multiple instances of it. That's possible and here it is a little snippet showing how:
var object = {
a: 2,
b: function(){
return this.a;
}
}
var extend = function(obj) {
return function() {
return Object.create(obj);
}
};
var Class1 = extend(object);
var ob1 = Class1();
ob1.a = 10;
var Class2 = extend(object);
var ob2 = Class2();
ob2.a = 23;
console.log(ob1.b(), ob2.b());
The result of the script is
10 23

Related

AngularJS - create object array where label is $translated

I have the following array:
vm.roles = ['ROLE1', 'ROLE2', 'ROLE3', 'ROLE4'];
and I need this form of array:
vm.translatedRoles = [{id:0, label:'Role1'}, {id:1, label:'Role2'}, ...]
Therefore I wrote this function to transfer from vm.roles to vm.translatedRoles.
My Problem now is that translatedRoles stays empty, so there are no objects in it. Does anyone know why?
function translateRoles() {
var translatedRoles = [];
for(var i = 0; i < vm.roles.length; i++) {
$translate(vm.roles[i]).then(function(text) {
var role = {};
role.id = i;
role.label = text;
translatedRoles.push(role);
});
}
return translatedRoles;
}
That can't work. $translate() returns a promise. The function passed to $translate is executed later, asynchronously, when the translations are available. So, the return statement happens before translatedRoles is populated by the function.
You need to return a promise of array, or hope that the translations are already available and use $translate.instant():
function translateRoles() {
var translatedRoles = [];
for (var i = 0; i < vm.roles.length; i++) {
translatedRoles.push({
id: i,
label: $translate.instant(vm.roles[i]);
});
}
return translatedRoles;
}

How do I access this array in backbone?

I’m new to Backbone, but I’ve successfully been able to define an array like this on one of my models:
buildMyArray: function() {
var self = this;
var myArray = {};
window.myLibrary.getStuff('myParameter', function(myStuff) {
for (var myKey in myStuff) {
if (myStuff.hasOwnProperty(myKey)) {
var myValue = myStuff[myKey];
myArray[myKey] = myValue;
}
}
self.set({ myArray: myArray });
});
}
However, how can I access that array from other properties? In other words, I want to do something like this:
checkArrayStuff: function(arrayKey) {
//loop through myArray and check value for arrayKey.
//var myArray1 = self.get(myArray);
//var myArray2 = this.get(myArray);
//var myArray3 = myArray;
//var myArray4 = this.myArray;
//var myArray5 = self.get('myArray');
//var myArray6 = this.get('myArray');
var myArray7 = self.myArray;
var can = myArray7[arrayKey];
return can;
}
I’ve tried several variations of self, this, with-and-without-quotes, with-and-without get-method, etc.
I guess you would have to do this
checkArrayStuff: function(arrayKey) {
return this.get('myArray')[arrayKey];
}
this.get('myArray') should work but it looks like your window.myLibrary.getStuff function is asynchronous. That means myArray won't be set until some time after buildMyArray returns. If you give us more context we can make a better recommendation of how to address this such as having buildMyArray call checkArrayStuff after it's done the .set(..) or having buildMyArray return a promise

How to extend returned objects in the list returned by $asArray?

I'm having trouble decorate the objects in my list returned by $asArray in angularfire with a new method (not decorating the array itself).
The angularfire documentation seems to suggest that the right way to do this is to override the $$added method in the factory for $FirebaseArray, returning a new object that either encapsulates or extends the snapshot that gets passed in to that method. From the documentation:
// an object to return in our JokeFactory
app.factory("Joke", function($firebaseUtils) {
function Joke(snapshot) {
this.$id = snapshot.name();
this.update(snapshot);
}
Joke.prototype = {
update: function(snapshot) {
// apply changes to this.data instead of directly on `this`
this.data = snapshot.val();
},
makeJoke: function() {
alert("Why did the " + this.animal + " cross the " + this.obstacle + "?");
},
toJSON: function() {
// since we didn't store our data directly on `this`, we need to return
// it in parsed format. We can use the util function to remove $ variables
// and get it ready to ship
return $firebaseUtils.toJSON(this.data);
}
};
return Joke;
});
app.factory("JokeFactory", function($FirebaseArray, Joke) {
return $FirebaseArray.$extendFactory({
// change the added behavior to return Joke objects
$$added: function(snap) {
return new Joke(snap);
},
// override the update behavior to call Joke.update()
$$updated: function(snap) {
this.$getRecord(snap.name()).update(snap);
}
});
});
However, when I do this in my code, nothing ever gets added to the array, although I can see from outputting to the console that it is getting called.
var printMessageObjConstructor = function(snap) {
this.$id = snap.name();
this.snapshot = snap;
this.$update = function(snap) {
this.snapshot = snap;
};
this.printMessage = function() {
return this.author + "'s question is: " + this.body;
};
};
var ref = new Firebase("https://danculley-test.firebaseio.com/questions");
//What Am I Doing Wrong Here?
var arrayFactory = $FirebaseArray.$extendFactory({
$$added: function(snap, prevChild) {
var x = new printMessageObjConstructor(snap);
console.log("I am being called from FirebaseDecoratedCtlOverloadAddedinNewObj.");
return x;
},
$createObject: function(snap) {
return new printMessageObjConstructor(snap);
},
$$updated: function(snap) {
var i = this.$indexFor(snap.name());
var q = this.$list[i];
q.$update(snap);
}
});
var sync = $firebase(ref, {arrayFactory:arrayFactory});
var list = sync.$asArray();
list.$loaded(function(list) {
$scope.questions = list;
});
I've set up a new plunk stripped down to show the issue with a couple other use cases that I've tried. (The actual method I'm adding is more complex and isn't related to the view, but I wanted to do something simple to reproduce the issue.)
I think the issue is that I don't quite understand what exactly $$added is supposed to return, or what additional behavior beside returning the value to be stored $$added is supposed to have. There also doesn't really seem to be an $$added on the prototype or on $FirebaseArray to call as a super to get the default behavior. Can someone point me in the right direction?
UPDATE
For the benefit of others, after reviewing the like that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}
For the benefit of others, after reviewing the link that Kato posted, I was able to solve the issue by adding the following, almost all copied directly from the source except for the commented line below.
$$added: function(snap, prevChild) {
var i = this.$indexFor(snap.name());
if( i === -1 ) {
var rec = snap.val();
if( !angular.isObject(rec) ) {
rec = { $value: rec };
}
rec.$id = snap.name();
rec.$priority = snap.getPriority();
$firebaseUtils.applyDefaults(rec, this.$$defaults);
//This is the line that I added to what I copied from the source
angular.extend(rec, printMessageObj);
this._process('child_added', rec, prevChild);
}
}

javascript: when declaring a prototype method: error is invalid left hand side for assignment

I am new to object oriented javascript. Trying to make an object constructor.
Here is my code
function Collection() {
this.ports = build_ports_collection();
this.all_things = build_things_collection();
this.added_things = function() {
this.added_things.total_added = 0;
var temp = this.all_things;
temp.splice($(sth).val(), 1);
this.added_things.all = temp;
};
};
Collection.ports.prototype.reload = function() {
Collection.ports = build_ports_collection();
};
Collection.all_things.prototype.reload = function() {
Collection.all_things = build_things_collection();
};
Collection.added_things.all.prototype.reload() = function() {
var temp = Collection.all_things;
temp.splice($(sth).val(), 1);
Collection.added_things.all = temp;
};
Collection.added_things.prototype.add_things = function() {
this.added_things.total_added++;
add_things();
};
Collection.added_things.prototype.remove_things = function() {
this.added_things.total_added--;
remove_things();
};
I am getting error in the line Collection.added_things.all.prototype.reload()=....
netbeans reports: invalid left hand side for assignment.
here my intention was to bind a method reload() to Collection.added_things.all so that it will be shared among all instances of Collection
What point i am missing ?
Not sure if this is the answer you're looking for, but this came to mind.
Collection.added_things.all.prototype.reload() = function() {
var temp = Collection.all_things;
temp.splice($(sth).val(), 1);
Collection.added_things.all = temp;
};
There, you are assigning stuff to the prototype of Collection.added_things.all, while
this.added_things = function() {
this.added_things.total_added = 0;
var temp = this.all_things;
temp.splice($(sth).val(), 1);
this.added_things.all = temp;
};
is the first to declare the .all on Collection.added_things - basically, you are trying to assign a value to a property/variable/pointer that does not exist until added_things is first called.

Using javascript prototype function to initialise variable in 'this' context

I'm finding it difficult to explain in words, so here's a snippet of code I'm trying out but Firefox/firebug goes into tailspin!
I'm trying to follow this and this as a guide. What I'm trying to do here is
new MyObject.Method('string',optionsArray);
optionsArray items are iterated and saved using the prototype function Set()
if(typeof(MyObj) == 'undefined') MyObj= {};
MyObj.Method = function initialise(id,options)
{
this.id = id;
this.options = options;
this.properties ={};
for (var i = 0; i < this.options.length; i++) // =>options.length=2 (correct)
{
var obj = this.options[i];
//get the keynames, pass with values to Set() to update properties
for (var keys in obj)
{
console.log(keys); //=> correctly prints 'property1' and 'currentValue'
this.Set(keys,obj); //=> this is i guess where it enters a loop?
}
}
}
//sets properties
MyObj.Method.prototype.Set = function (name, value)
{
this.properties[name.toLowerCase()] = value;
}
and in my html page script block, i have
window.onload = function () {
var options = [
{ property1: {
show: true,
min: 0,
max: 100
}
},
{
currentValue: {
show: true,
colour: 'black'
}
}
];
var myObj = new MyObj.Method('someDivId',options);
}
please advise if I'm over complicating the code. I think checking for hasOwnProperty would help.
This should be a cleaner way of achieving what you want:
function MyObj(id, options) { // a function that will get used as the constructor
this.id = id;
this.options = options;
this.properties = {};
this.set(options); // call the set method from the prototype
}
MyObj.prototype.set = function(options) { // set the options here
for(var i = 0, l = options.length; i < l; i++) {
var obj = this.options[i];
for(var key in obj) {
if (obj.hasOwnProperty(key)) { // this will exclude stuff that's on the prototype chain!
this.properties[key] = obj[key];
}
}
}
return this; // return the object for chaining purposes
// so one can do FooObj.set([...]).set([...]);
};
var test = new MyObj('simeDivId', [...]); // create a new instance of MyObj
test.set('bla', [...]); // set some additional options
Note: For what hasOwnProperty is about please see here.
I made a declaration for MyObj and removed the function name initialise since you're obviously declaring this function to be a property of MyObj. Your final code will then be like below, and that runs for me just fine. Please note that you cannot actually call the function until after you declare the prototype function because else the object will have no notion of the Set function.
var MyObj = {};
MyObj.Method = function (id,options)
{
this.id = id;
this.properties ={};
for (var i = 0; i < options.length; i++) // =>options.length=2 (correct)
{
var obj = options[i];
//get the keynames, pass with values to Set() to update properties
for (var keys in obj)
{
console.log(keys); //=> correctly prints 'property1' and 'currentValue'
this.Set(keys,obj); //=> this is i guess where it enters a loop?
}
}
}
MyObj.Method.prototype.Set = function (name, value)
{
this.properties[name.toLowerCase()] = value;
}
var options = [
{ property1: {
show: true,
min: 0,
max: 100
}
},
{
currentValue: {
show: true,
colour: 'black'
}
}
];
var myObj = new MyObj.Method('someDivId',options);
var MyObj = {};
MyObj.Method = function initialise(id,options) {
this.id = id;
this.options = options;
this.properties = {};
for (var i = 0; i < this.options.length; i++)
{
var obj = this.options[i];
for (var keys in obj) {
this.Set(keys,obj[keys]);
//*fix obj => obj[keys]
// (and it should be singular key rather then keys
}
}
console.log(this.properties) // will output what you want
}
//sets properties
MyObj.Method.prototype.Set = function (name, value) {
this.properties[name.toLowerCase()] = value;
}
var options = [{
property1: {
show: true,
min: 0,
max: 100
}
},{
currentValue: {
show: true,
colour: 'black'
}
}];
var myObj = new MyObj.Method('someDivId',options);
this should work problem is you had your myObj = new MyObj... outside your onload event and options was out of its scope as it was declared as private variable to the anonymous function bound to the onload event.
I've fixed also the way you was copying the values to the properties as it doubled the names of the property and made it a bit messy.

Resources