Javascript turning JSON string into instance of function - javascript

I have a bunch of JSON string returned from an ajax call in a specific format and when starting to convert them all into my own Javascript object, I start to wonder if there is any easier way since we're talking Javascript here.
I'll have var manyOfThem = [ { name: 'a' }, { name: 'b' }, { name: 'c' } ];
And I'd like to easily associate each of these objects with my functions so that I can do things like:
myClass.prototype.doSomething = function() {
// do something to this.name
};
$.each(manyOfThem, function(index, item) {
item.doSomething();
});
I guess my concern is, I would not want to (because its repetitive) do this:
var myClass = function(item) {
this.name = item.name;
// do the same for the rest of item's potentially 20 properties
};
var oneOfThem = new myClass(manyOfThem[0]); // I think this is redundant....
oneOfThem.doSomething();
Anyhow, if there is also (security?) reasons why I'd just have to suck it up and do them all manually please share as well, thanks!

You mean, something like (see jsfiddle) :
var MyClass = function() {};
MyClass.prototype = {
doSomething: function() {
alert(this.name);
}
};
Then
var manyObj = $.map(manyOfThem, function(obj) {
return $.extend( new MyClass(), obj );
});
So you can call :
manyObj[0].doSomething(); // alert("a")
However, this approach will not preserve a direct copy with the manyOfThem object. (In the example above, changing manyOfThem[0].name = "foo"; will not affect manyObj[0] and a call to manyObj[0].doSomething(); will still alert "a". To preserve a direct reference to your object, do this :
var manyObj = $.map(manyOfThem, function(obj) {
function F() {};
F.constructor = MyClass;
F.prototype = obj;
$.extend(F.prototype, new MyClass());
return new F();
});
manyObj[0].doSomething(); // alert("a")
manyOfThem[0].name = "foo"; // modify the referenced object
manyObj[0].doSomething(); // alert("foo") ..also modifies the behaviour of the instance

One solution without using a class is
var manyOfThem = [ { name: 'a' }, { name: 'b' }, { name: 'c' } ];
function doSomething(){
console.log(this.name)
}
$.each(manyOfThem, function(index, item) {
doSomething.call(item);
});
Demo: Fiddle
If you want to create an instance of type MyClas then
var manyOfThem = [ { name: 'a' }, { name: 'b' }, { name: 'c' } ];
function MyClass(item){
$.extend(this, item);
}
MyClass.prototype.doSomething = function(){
console.log(this.name)
}
$.each(manyOfThem, function(index, item) {
var obj = new MyClass(item);
obj.doSomething()
});
Demo: Fiddle

You can do
var myClass = function(item){
for( i in item){
if (item.hasOwnProperty(i)){
this[i] = item[i];
}
}
};
This should reduce the repetitive assignments in myClass constructor.

Related

Can I navigate upwards through a javascript object in the same way I can through the DOM? [duplicate]

var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
},
GetUserName: function() { }
}
}
You can't.
There is no upwards relationship in JavaScript.
Take for example:
var foo = {
bar: [1,2,3]
}
var baz = {};
baz.bar = foo.bar;
The single array object now has two "parents".
What you could do is something like:
var User = function User(name) {
this.name = name;
};
User.prototype = {};
User.prototype.ShowGreetings = function () {
alert(this.name);
};
var user = new User('For Example');
user.ShowGreetings();
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
alert(this.Parent.Name); // "this" is the Methods object
},
GetUserName: function() { }
},
Init: function() {
this.Methods.Parent = this; // it allows the Methods object to know who its Parent is
delete this.Init; // if you don't need the Init method anymore after the you instanced the object you can remove it
return this; // it gives back the object itself to instance it
}
}.Init();
Crockford:
"A privileged method is able to access the private variables and
methods, and is itself accessible to the public methods and the
outside"
For example:
function user(name) {
var username = name;
this.showGreetings = function()
{
alert(username);
}
}
You can try another approach using a closure:
function userFn(name){
return {
Methods: {
ShowGreetings: function() {
alert(name);
}
}
}
}
var user = new userFn('some user');
user.Methods.ShowGreetings();
Old question but why can't you just do something like this :
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function() {
// at this point i want to access variable "Name",
//i dont want to use user.Name
// **please suggest me how??**
var thisName = user.Name; //<<<<<<<<<
},
GetUserName: function() { }
}
}
Because you will only call user.Methods.ShowGreetings() after the user has been instantiated. So you will know about the variable 'user' when you want to use its name ?
As others have said, with a plain object it is not possible to lookup a parent from a nested child.
However, it is possible if you employ recursive ES6 Proxies as helpers.
I've written a library called ObservableSlim that, among other things, allows you to traverse up from a child object to the parent.
Here's a simple example (jsFiddle demo):
var test = {"hello":{"foo":{"bar":"world"}}};
var proxy = ObservableSlim.create(test, true, function() { return false });
function traverseUp(childObj) {
console.log(JSON.stringify(childObj.__getParent())); // returns test.hello: {"foo":{"bar":"world"}}
console.log(childObj.__getParent(2)); // attempts to traverse up two levels, returns undefined because test.hello does not have a parent object
};
traverseUp(proxy.hello.foo);
Very late to the party, but this works
var user = {
Name: "Some user",
Methods() {
return {
that: this,
ShowGreetings: function() {
console.log(this.that.Name)
},
GetUserName: function() { }
}
}
}
user.Methods().ShowGreetings() // Some user
David Dorward's right here. The easiest solution, tho, would be to access user.Name, since user is effectively a singleton.
ES6 Classes
One simple solution would be to create a Class with methods!
class User {
// Assign properties when an instance
// is created using the `new` keyword
constructor(name) {
this.name = name;
}
// Methods:
showGreetings() {
console.log(`Hello, ${this.name}!`);
}
getUserName() {
return this.name;
}
// Or rather, use Getters:
get username() {
return this.name;
}
}
// Create a new user:
const user = new User("Praveen");
// Use methods:
user.showGreetings(); // "Hello, Praveen!"
console.log(user.getUserName()); // "Praveen"
console.log(user.username); // "Praveen"
Why the above suggestion? Mostly because:
you cannot reference a parent Object from a child Object directly
const User = {
name: "Some user", // hardcoded stuff? Is this an intentional Singleton?
methods: { // <<< Child Object of User
sayName() {
// Sadly, `this` refers to `methods`, not to `user`:
console.log(this); // methods{}
console.log(User.name); // "Some user" // Get Singleton's name
// ... but that's not what you want.
}
}
};
User.methods.sayName();
// ^^^^^^^ Why would you want this `methods` anyways?!
and it makes no sense to hardcode Strings (like "Some user") inside an Object Singleton — which could actually be a reusable function Object.
If you want to associate a child Node to a parent Node — read this answer (Get value of parent Object).
How about this way?
user.Methods.ShowGreetings.call(user, args);
So you can access user.Name in ShowGreetings
var user = {
Name: "Some user",
Methods: {
ShowGreetings: function(arg) {
console.log(arg, this.Name);
},
GetUserName: function() { }
},
Init: function() {
this.Methods.ShowGreetings.call(this, 1);
}
};
user.Init(); // => 1 "Some user"
As a variant:
var user = (obj => {
Object.keys(obj.Methods).map(option => {
const currOpt = obj.Methods[option];
if (currOpt instanceof Function) {
obj.Methods[option] = currOpt.bind(obj);
};
});
return obj;
})({
Name: "Some user",
Methods: {
Greeting: function () { return this.Name },
GetUserName: function() { console.log(this) }
},
});
But I don't know why somebody can use this strange approach
I know I'm very late.
I wrote this simple method. Let's say you have:
{
subObj: {
x:'hello_world';
}
}
Then, if you want a reference to the bigger object from subObj, you can convert it to a function, and utilize this.
var tmpVal=reference_to_subObj; //keep value of subObj safe
reference_to_subObj=function(){return this;}//this returns the scope, here the parent
var parent=reference_to_subObj(); //call the function
reference_to_subObj=tmpVal; delete tmpVal; //set things back to normal
//Now you have variable 'parent'.
I used a Function() constructor because it let me create the function as a string, so I could pass a string as code.
function findParent(stringReference) {
Function(/*same as above, except filled in all reference_to_subObj with stringReference.*/
//stringReference is a stringified version of dot or bracket notation.
So I could call findParent('obj.subObj').
// Make user global
window.user = {
name: "Some user",
methods: {
showGreetings: function () {
window.alert("Hello " + this.getUserName());
},
getUserName: function () {
return this.getParent().name;
}
}
};
// Add some JavaScript magic
(function () {
var makeClass = function (className) {
createClass.call(this, className);
for (key in this[className]) {
if (typeof this[className][key] === "object") {
makeClass.call(this[className], key);
}
}
}
var createClass = function (className) {
// private
var _parent = this;
var _namespace = className;
// public
this[className] = this[className] || {};
this[className].getType = function () {
var o = this,
ret = "";
while (typeof o.getParent === "function") {
ret = o.getNamespace() + (ret.length === 0 ? "" : ".") + ret;
o = o.getParent();
}
return ret;
};
this[className].getParent = function () {
return _parent;
};
this[className].getNamespace = function () {
return _namespace;
}
};
makeClass.call(window, "user");
})();
user.methods.showGreetings();
I ran across this old post trying to remember how to solve the problem. Here is the solution I used. This is derived from Pro JavaScript Design Patterns by Harmes and Diaz (Apress 2008) on page 8. You need to declare a function and then create a new instance of it as shown below. Notice the Store method can access "this".
function Test() {
this.x = 1;
}
Test.prototype = {
Store: function (y) { this.x = y; },
}
var t1 = new Test();
var t2 = new Test();
t1.Store(3);
t2.Store(5);
console.log(t1);
console.log(t2);
Like #Quentin said, there is no upwards relationship in JS. However try this workaround;
foo = { bar: {parent: foo} };
console.log(foo);
console.log(foo.bar.parent);
which is also similar to;
function Foo(){
this.bar = {parent: this}
}
foo = new Foo();
console.log(foo);
console.log(foo.bar.parent);

Getting Object Key Name from inside function?

Say I have an object like below:
var obj = {};
obj.test = function() { console.log(?); }
Is there anyway to print out "test", the key that this function is value of, but not know the obj name in advance?
Not really. Relationships in JS are one-way.
You could search for a match…
var obj = {};
obj.not = 1;
obj.test = function() {
var me = arguments.callee;
Object.keys(obj).forEach(function(prop) {
if (obj[prop] === me) {
console.log(prop);
}
});
};
obj.test();
But look at this:
var obj = {};
obj.not = 1;
obj.test = function() {
var me = arguments.callee;
Object.keys(obj).forEach(function(prop) {
if (obj[prop] === me) {
console.log(prop);
}
});
};
obj.test2 = obj.test;
obj.test3 = obj.test;
window.foo = obj.test;
obj.test();
The same function now exists on three different properties of the same object … and as a global.
Might be a bit of a convoluted solution, but this might be useful -
You can have a method that will add functions to your object at a specific key. Using the bind method, we can predefine the first argument to the function to be the key that was used to add it.
The function that I am adding to the key is _template, it's first argument will always be the key that it was added to.
var obj = {};
function addKey(key) {
obj[key] = _template.bind(null, key)
}
function _template(key, _params) {
console.log('Key is', key);
console.log('Params are',_params);
}
addKey('foo')
obj.foo({ some: 'data' }) // this will print "foo { some: 'data' }"
Reference - Function.prototype.bind()
try this Object.keys(this) and arguments.callee
var obj = {};
obj.test = function() {
var o = arguments.callee;
Object.values(this).map((a,b)=>{
if(a==o){
console.log(Object.keys(this)[b])
}
})
}
obj.one = "hi"
obj.test()
You can get the name of the method called with
arguments.callee.name
var a ={ runner_function : function(){ console.log(arguments.callee.name ); } };
a.runner_function() //It will return "runner_function"

How to access form data from a setter without using object literal values?

I need to add setter to the below JavaScript Module:
In the below code I am simply returning the form data to the module object.
I need to add setter functionality so that I can do minimal check on the user input.
var Mod = (function(){
var module = {};
var element = document.forms.[0];
Object.defineProperty(module, 'Country', {
get: function () {
return element.txtCountry.value;
}
});
Object.defineProperty(module, 'City', {
get: function () {
return element.txtCity.value;
}
});
return module;
})();
However, all of the examples I have come across, including those on MDN shows an object with literal values:
Like this one:
var module = {
Country: "United States",
get function() {
return this.Country;
},
set function(x) {
this.Country = x + ' ' + somethingElse;
}
};
How do I add the setter to return data to the object without literal object members?
Finally I am calling the module like this:
var btn = document.getElementById( 'btnDataEntry' );
var result = document.getElementById('result');
btn.addEventListener('click', function(e) {
var t = document.createTextNode(Mod.Country + ',' + Mod.City);
result.appendChild(t);
e.preventDefault();
}, false);
Update (Additional Info):
In the most simplest form I want to perform checks in the setter, something like this:
var Mod = (function(){
var module = {};
var element = document.forms.dataEntry;
Object.defineProperty(module, 'Country', {
get: function () {
return Country;
},
set: function(val) {
if( val == 'A') {
val = element.txtCountry.value;
}
}
});
return module;
})();
Update: (Solution).
So as simple as this may seem, it can become confusing because JavaScript is more abstract when it comes to how one can accomplish certain task.
The problem is, when using setter in an Object.defineProperty() method, you have to pass the value using a dot notation to the object, and by also using a variable within the scope of the function to emulate a private member.
If you look at my previous code, you will see that I was passing the form data directly within the getter, this defeats the entire purpose of having a getter/setter.
Here is a complete working code: Based on readings and example from the following book: The Principles of Object-Oriented JavaScript: By Nicholas C. Zakas.
Code:
var LocationData = (function(){
var location = {};
//Private member to eliminate global scope
var _country;
Object.defineProperty(location, "Country", {
get: function() {
return this._country;
},
set: function(value) {
if(value === 'A') {
this._country = value;
} else {
this._country = 'X';
}
}
});
return location;
})();
var btn = document.getElementById( 'btnDataEntry' );
var result = document.getElementById('result');
btn.addEventListener('click', function(e) {
var element = document.forms[0];
//Pass the value to the method
LocationData.Country = element.txtCountry.value;
var t = document.createTextNode(LocationData.Country);
result.appendChild(t);
e.preventDefault();
}, false);
Define the setter in the same defineProperty call where you define the getter:
Object.defineProperty(module, 'City', {
get: function () {
return element.txtCity.value;
},
set: function (value) {
// do minimal check
element.txtCity.value = value;
}
});

Creating a function with properties

Sorry, I don´t know the name of this.
I want to have a function and an object with properties in only one variable.
Here is how it works:
var obj = function() {
return "foo";
};
obj.prop = "bar";
obj(); // => "foo"
obj.prop; // => "bar"
This works fine, but I would like to change the order of this:
var obj = { prop: "bar" };
obj = function() {
return "foo";
};
obj(); // => "foo"
obj.prop; // => undefined
Is there a way to do this?
I want do do this because I have a lot of properties to add to the object:
var obj = function() {
return "foo";
};
obj.prop1 = "bar1";
obj.prop2 = "bar2";
obj.prop3 = "bar3";
obj.prop4 = "bar4";
obj.prop5 = "bar5";
obj.prop6 = "bar6";
obj.prop7 = "bar7";
//...
This isn't possible because when you do:
obj = function() {
return "foo";
};
...you're assigning the variable obj to the new function, so it no longer points to the original object you created ({ prop: "bar" }) at all.
So if you want to add properties to a function object, you must always create the function first, then add properties.
As an alternative, you could do something like this:
var props = {
prop1: "bar1",
prop2: "bar2"
};
var obj = function() {
return "foo";
};
for (var key in props) {
obj[key] = props[key];
}
Or if you happen to have jQuery available (and don't have Object.assign available):
jQuery.extend(obj, props);
(Of course there are shims available for Object.assign, which would allow #Pointy's answer to work in older browsers.)
If you want to do this with one statement, ES2015 (and some libraries) let you do:
var obj = Object.assign(
function() { /* ... */ },
{ "hello": "world" }
);
Which will give you obj as a function with the property "hello". Note that this is really just the same thing as the separate assignment, but it's all wrapped up as one overall expression, which is nice because it means you can do something like
return Object.assign(function() { /* whatever */ }, {
prop: whatever,
// ...
});
I also agree with Grundy, but you could do something like that:
var x = function(){
var obj = {};
return {
objToReturn: obj,
objFunction: function(){return 'foo';},
addItemsToObject: function (key, value) {
obj[decodeURIComponent(key)] = value;
}
}
};
I honestly don't know if that's what you really want, but in that case you can execute the "x" function and after you can access the
"objFunction", the "objToReturn" or the "addItemsToObject" function.
So it will be something like that:
var y = x();
for (propertie in yourProperties){
y.addItemsToObject
(propertie, yourProperties[decodeURIComponent(propertie)]);
}
And then:
y.objFunction();
'foo'
Hope that helps.

Javascript access parent properties

How can I get parent options?
I would like to access a global myObject options
var myObject = {
method: function(){
this.options = {};
},
property: {
propertyMethod: function(){
alert(this.options);
}
}
}
myObject.method();
myObject.property.propertyMethod();
If you mean, you want to access myObject's options property from within property.propertyMethod, there's no way to do that except by taking advantage of the fact that propertyMethod is a closure over the myObject variable, e.g.:
var myObject = {
method: function(){
this.options = {};
},
property: {
propertyMethod: function(){
alert(myObject.options); // <=== Change is here
}
}
}
myObject.method();
myObject.property.propertyMethod();
...which isn't usually a good idea. :-) Instead, you may want to design your object differently. For instance:
var myObject = (function() {
var obj = {
method: function(){
obj.options = {};
},
property: {
propertyMethod: function(){
alert(obj.options);
}
}
};
return obj;
})();
myObject.method();
myObject.property.propertyMethod();
That way, you're using the execution context of the call to the function. But if you're going to do that, maybe take it to the next step:
function makeObject() {
var obj = {
method: function(){
obj.options = {};
},
property: {
propertyMethod: function(){
alert(obj.options);
}
}
};
return obj;
}
var myObject = makeObject();
myObject.method();
myObject.property.propertyMethod();
...so you can make more than one. Or even make a true constructor:
function MyObject() {
var obj = this;
obj.method = function(){
obj.options = {};
};
obj.property = {
propertyMethod: function(){
alert(obj.options);
}
};
}
var myObject = new MyObject();
myObject.method();
myObject.property.propertyMethod();
...although since you're not leveraging the prototype, there's no much reason to make it a constructor function.
You can use call to bind this to myObject
myObject.property.propertyMethod.call(myObject);

Categories