Copy object properties in JavaScript - javascript

I have some custom Object definitions like:
var Class1 = function () { this.value = ''; };
var Class2 = function () { this.data = ''; };
Class1.prototype = {
setObject: function () {
for (var prop in this){
if (typeof obj[prop] != 'undefined')
this[prop] = obj[prop];
}
}
}
Class2.prototype = {
setObject: function () {
for (var prop in this){
if (typeof obj[prop] != 'undefined')
this[prop] = obj[prop];
}
}
}
Is there a way to have this method setObject by default to all clases?
Is it better to (simulate) inherit that function from the Object type in JavaScript or is it better to use a global function or to define it one by one?

If you're going to be using a library such as jQuery or underscore, you'll already have access to a resilient extend method (see $.extend, and _.extend), so I would say that there's no reason to reinvent the wheel on these custom object types.
Otherwise, you can have Class1 and Class2 inherit from a common base class:
function BaseClass() {
...
}
BaseClass.prototype = {
setObject: function (obj) {...}
};
function Class1() {
...
}
Class1.prototype = new BaseClass();
function Class2() {
...
}
Class2.prototype = new BaseClass();
var a = new Class1();
a.setObject({...});
var b = new Class2();
b.setObject({...});
Or, if those objects should not contain a common ancestor, you could define them to use the same setObject function reference:
function setObject(obj) {
...
}
function Class1() {
...
}
Class1.prototype = {
setObject: setObject
};
function Class2() {
...
}
Class2.prototype = {
setObject: setObject
}

I am not sure if you know that, but there are no classes or methods in Javascript. There are only objects, functions and a special property called "prototype".
The common way of simulating classes is this:
var Class = function () { this.prop = "hi" };
Class.prototype.doMethod = function () { this.prop = "hi2"; };
Class.prototype.setObject: function () {
for (var prop in this){
if (typeof obj[prop] != 'undefined')
this[prop] = obj[prop];
}
}
// those classes "inherit" from Class
var Class1 = function () { Class.call(this); this.value = ''; };
Class1.prototype = new Class();
var Class2 = function () { Class.call(this); this.data = ''; };
Class2.prototype = new Class();

Ivan showed how to inherit from an object. More information about using constructor functions and inherritance can be found here: Prototypical inheritance - writing up
You can use a mixin pattern as well:
var mixIn=function(target,source){
for(fn in source){
if(source.hasOwnProperty(fn)){
target.prototype[fn]=source[fn];
}
}
};
var ObjectSettable = {
setObject: function () {
for (var prop in this){
if (typeof obj[prop] != 'undefined')
this[prop] = obj[prop];
}
}
};
var Class1 = function () { this.value = ''; };
//... Class1.prototype stuff
mixIn(Class1,ObjectSettable);

Related

Can't enumerate getters/setters properties

I am working on some reflections code to try to scrape out properties and functions, but I can't seem to get the getters/setters at all.
The reflection code I have for properties is:
Reflector = function() { };
Reflector.getProperties = function(obj) {
var properties = [];
var proto = obj;
while (proto != Object.prototype) {
console.log('Scrapping proto: ', proto);
for (var prop in proto) {
console.log('typeof ' + prop + ": ", typeof obj[prop]);
if (typeof obj[prop] != 'function') {
properties.push(prop);
}
}
proto = Object.getPrototypeOf(proto);
}
return properties;
};
And a sample of it running (with my debug messages) is:
var SimpleTestObject = function() {
this.value = "Test1";
this._hiddenVal = "Test2";
this._readOnlyVal = "Test3";
this._rwVal = "Test4";
};
SimpleTestObject.prototype = {
get readOnlyVal() {
return this._readOnlyVal;
},
get rwVal() {
return this._rwVal;
},
set rwVal(value) {
this._rwVal = value;
},
func1: function() {
// Test
}
};
SimpleTestObject.func2 = function(test) { /* Test */ };
SimpleTestObject.outsideVal = "Test5";
var props = Reflector.getProperties(SimpleTestObject);
console.log('props: ', props);
console.log('Object.getOwnPropertyNames: ', Object.getOwnPropertyNames(SimpleTestObject));
console.log('rwVal property descriptor: ', Object.getOwnPropertyDescriptor(SimpleTestObject, 'rwVal'));
console.log('rwVal (2) property descriptor: ', Object.getOwnPropertyDescriptor(Object.getPrototypeOf(SimpleTestObject), 'rwVal'));
What I expect to see as output to my Reflection.getProperties(SimpleTestObject) is ['readOnlyVal', 'rwVal', 'outsideVal'], but instead I am only seeing outsideVal. Further, when I tried to using getOwnPropertyDescriptor() to see if the rwVal was enumerable, it came back as undefined. So, thinking maybe it somehow got showed into the prototype above, I tried going up a level and still got undefined.
For enumerate the getters please use Object.keys or Object.getOwnPropertiesNames on prototype instead of constructor or/and instance:
function readGetters(obj) {
var result = [];
Object.keys(obj).forEach((property) => {
var descriptor = Object.getOwnPropertyDescriptor(obj, property);
if (typeof descriptor.get === 'function') {
result.push(property);
}
});
return result;
}
var SimpleTestObject = function() {
this.value = "Test1";
this._hiddenVal = "Test2";
this._readOnlyVal = "Test3";
this._rwVal = "Test4";
};
SimpleTestObject.prototype = {
get readOnlyVal() {
return this._readOnlyVal;
},
get rwVal() {
return this._rwVal;
},
set rwVal(value) {
this._rwVal = value;
},
func1: function() {
}
};
SimpleTestObject.func2 = function(test) { /* Test */ };
SimpleTestObject.outsideVal = "Test5";
// For constructor
console.log(readGetters(SimpleTestObject.prototype));
// For instance
var instance = new SimpleTestObject();
console.log(readGetters(Object.getPrototypeOf(instance)));
you can enumerate setter/getter properties by Object.getOwnPropertyNames if you use getter and setter with Object.defineProperty or Object.defineProperties
const _name = Symbol();
const _age = Symbol();
class Dog {
constructor(name, age) {
Object.defineProperties(this, {
name: {
// you can set enumerable true explicitly if you want
//enumerable:true ,
set(value) {
this[_name] = name;
},
get() {
return this[_name];
}
},
age: {
set(value) {
this[_age] = age;
},
get() {
return this[_age];
}
},
book: {
get() {
return "Book"
}
}
});
this.name = name;
this.age = age;
}
}
const dog = new Dog("spike", 3);
console.log(Object.getOwnPropertyNames(dog));

implementing extend method in javascript

By looking through the code of BackboneJS, i am interested about extend the implemented. by when i try to make it myself i am stuck. my code is the following.
var extend = function(child) {
var base = this;
if(child) {
for(var prop in child) {
base[prop] = child[prop];
}
}
return base;
};
var Test = Mod.Test = function() {
this.data = {};
}
Test.prototype.set = function(key, value) {
this.data[key] = value;
}
Test.prototype.get = function(key) {
return this.data[key];
}
Test.extend = extend;
when i try like this i am not able to attach hello method to Mod.Test
var testObj = new Mod.Test.extend({
hello : function() {
console.log('hello');
}
});
How is it possible. how its implemented in backbonejs.
Backbone's extend method accepts two parameters - instance properties and static properties. The first ones are copied to the instance being created, the second are assigned to the instance's prototype. Usually you should invoke the extend method without the new operator but in this case here is a working version of your code:
var extend = function(child) {
var base = this;
if(child) {
for(var prop in child) {
base[prop] = child[prop];
}
for(var prop in child) {
base.prototype[prop] = child[prop];
}
}
return base;
};
var Test = Backbone.Model.Test = function() {
this.data = {};
}
Test.prototype.set = function(key, value) {
this.data[key] = value;
}
Test.prototype.get = function(key) {
return this.data[key];
}
Test.extend = extend;
and then:
Test = Backbone.Model.Test.extend({
hello : function() {
console.log('hello');
}
});
var testObj = new Test;

How to "new" a returned function in Javascript

I am trying to simulate a namespace feature in Javascript.
var com = {};
com.domain = {};
com.domain.system = {};
com.domain.net = {};
com.domain.net.ip = {};
com.domain.net.ip.tcp = {};
com.domain.net.ip.udp = {};
com.domain.net.ip.ssl = {};
com.domain.util = {};
com.domain.util.timer = {};
com.domain.plugins = {};
com.domain.session = {};
com.domain.io = {};
com.domain.algorithm = {};
com.domain.debug = {};
This is the namespaces declaration. Later I will add functions to these namespaces.
This is my selector function:
For a convenient way to use namespaces, I add a function named $. This function will walk all namespaces in com. If the selected name exists, return the object.
function $ (selector) {
function digger (namespace, selector) {
for (var prop in namespace) {
if (typeof namespace[prop] == "array" || typeof namespace[prop] == "object") {
if (prop == selector) {
return namespace[prop];
}
var dig = digger(namespace[prop], selector);
if (dig != null) {
return dig;
}
} else {
if (prop == selector) {
return namespace[prop];
}
}
}
}
return digger (com, selector);
}
After that, I add a timer to namespace com.doamin.util.
com.domain.util.timer = function () {
this._handle = new InnerObj.SystemTimer(io);
return this;
};
com.domain.util.timer.prototype.expiresFromNow = function (seconds, cbHandler) {
this._handle.ExpiresFromNow (seconds, cbHandler);
};
com.domain.util.timer.prototype.wait = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.expiresAt = function (seconds, cbHandler) {
this._handle.Wait (seconds, cbHandler);
};
com.domain.util.timer.prototype.cancel = function () {
this._handle.Cancel ();
};
Usage:
1. var timer = new com.domain.util.timer (); OK
timer.expiresAt (1, {}); OK
2. var func = $("timer"); OK
var timer = new func (); OK
timer.expiresAt (1, {}); OK
But but but but but
var timer = new $("timer") (); NG
Can anyone tell me why the last new function is not working?
Try var timer = new ($("timer"))();.
Your question is not clear but I guess since $("timer") returns a function, you want a new instance of the result of $("timer") and not a new instance of $().

Javascript convert function declared as dict of functions to prototype

What I'm trying to do is this:
My base code:
var Obj = function() {
this.do = function() {};
this.stop = function() {};
this.kill = function() {};
};
Obj.prototype.load = function() {};
The desired conversion:
var ConvObject = function() { };
ConvObject.prototype = (typeof Obj == "function")? new Obj : Obj;
This example works (for the conversion part). In ConvObject, all methods of Obj are there. But in my case, I DO NOT want to execute the default constructor of Obj. I would prefer to avoid this. Indeed, I do not want to execute new Obj.
I've try differents ways to accomplish this. Here is the best answer I could find by now:
var getSizeOf = function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
var ConvObject = function() { };
if ((typeof Obj == "function") && getSizeOf(Obj.prototype) == 0) {
ConvObject.prototype = new Obj;
}
else {
ConvObject.prototype = (typeof Obj == "function")? Obj.prototype : Obj;
}
This works when Obj looks like this:
var Obj = new function() {};
Obj.prototype.do = function() {};
Obj.prototype.stop = function() {};
Obj.prototype.kill = function() {};
Obj.prototype.load = function() {};
Or if it looks like this:
var Obj = function() {
this.do = function() {};
this.stop = function() {};
this.kill = function() {};
this.load = function() {};
};
But, this solution fails when I have the base code above. How can I avoid this call to the default constructor?
Thanks for the help!
Use Object.create() (or its polyfill) to inherit directly from Obj.prototype.
To "inherit" instance methods from the Obj constructor, you should call it on every ConvObject: Very simple Javascript inheritance. You would need to do this anyway when these methods are instance-specific, otherwise they should be on the prototype.

Javascript Metaprogramming

Is there a way to specify something similar to the following in javascript?
var c = {};
c.a = function() { }
c.__call__ = function (function_name, args) {
c[function_name] = function () { }; //it doesn't have to capture c... we can also have the obj passed in
return c[function_name](args);
}
c.a(); //calls c.a() directly
c.b(); //goes into c.__call__ because c.b() doesn't exist
Mozilla implements noSuchMethod but otherwise...no.
No, not really. There are some alternatives - though not as nice or convenient as your example.
For example:
function MethodManager(object) {
var methods = {};
this.defineMethod = function (methodName, func) {
methods[methodName] = func;
};
this.call = function (methodName, args, thisp) {
var method = methods[methodName] = methods[methodName] || function () {};
return methods[methodName].apply(thisp || object, args);
};
}
var obj = new MethodManager({});
obj.defineMethod('hello', function (name) { console.log("hello " + name); });
obj.call('hello', ['world']);
// "hello world"
obj.call('dne');
Almost 6 years later and there's finally a way, using Proxy:
const c = new Proxy({}, {
get (target, key) {
if (key in target) return target[key];
return function () {
console.log(`invoked ${key}() from proxy`);
};
}
});
c.a = function () {
console.log('invoked a()');
};
c.a();
c.b();
No.

Categories

Resources