I could create an object with some methods, and later add a property to it as follows:
var myObj = (function () {
var my = {};
my.method1=function(){}
my.method2=function(){}
my.method3=function(){}
return my;
}());
myObj.myProperty=123;
How could I create the object first and add a property, and then later add the methods afterwards?
myObj={};
myObj.myProperty=123;
//How do I add the above methods to myObj?
I guess there are two solutions:
Merge the objects:
var myObj = {...};
// ...
var objWithMethods = (function() { ... }());
Object.assign(myObj, objWithMethods);
(Object.assign is an ES6 methods. A polyfill can be found in the link, libraries often also provide a method with similar behavior).
Pass the object the methods should be assigned to as argument:
var myObj = {};
myObj = (function (obj) {
var my = obj || {};
my.method1=function(){}
my.method2=function(){}
my.method3=function(){}
return my;
}(myObj));
You can do an extend operation using an existing object
var myObj = {...}
var myAdditionalMethods = { someMethod : function(){ } }
//extend the object
for(var i in myAdditionalMethods)
if(!myObj.hasOwnProperty(i))
myObj[i] = myAdditionalMethods[i];
there are a lot of libraries that have this functionality built in, but that is how you would do it without one
Even prototype can add the functions to original object.
var myObj = function() {
this.myProperty = 123;
}
myObj.prototype.method1 = function method1() {
alert("method1")
}
myObj.prototype.method2 = function method2() {
alert("method2")
}
var newObj = new myObj();
newObj.method1();
newObj.method2();
console.log(newObj)
Related
I'm always getting Cannot set property 'saySomething' of undefined but why?
Am I making a mistake somewhere?
var Person = new Object();
Person.prototype.saySomething = function ()
{
console.log("hello");
};
Person.saySomething();
Debugging tip: You get this ..of undefined errors when you try to access some property of undefined.
When you do new Object(), it creates a new empty object which doesn't have a prototype property.
I am not sure what exactly are we trying to achieve here but you can access prototype of function and use it.
var Person = function() {};
Person.prototype.saySomething = function() {
console.log("hello");
};
var aperson = new Person();
aperson.saySomething();
The prototype property exists on functions, not on instantiated objects.
var Person = new Object();
console.log(Person.prototype); // undefined
var Person2 = function () {}
console.log(Person2.prototype); // {}
This is useful because things put on the prototype of a function will be shared by all object instances created with that function (by using new).
var Person = function() {};
Person.prototype.saySomething = function() {
console.log("hello");
};
console.log(
new Person().saySomething === Person.prototype.saySomething // true. they are the same function
);
If all you want is to add a method to the person object, there's no need for a prototype:
var Person = {};
Person.saySomething = function() {
console.log("hello");
};
Person.saySomething();
You can even use object literal syntax:
var Person = {
saySomething: function() {
console.log("hello");
}
};
Person.saySomething();
i was trying out some code thought of posting it, might help others.
<script>
var MODULE = {};
MODULE = (function (my) {
my.anotherMethod = function () {
console.log("hello ");
};
my.newMethod = function(){
console.log("hi new method ");
}
return my;
}(MODULE));
MODULE.anotherMethod();
MODULE.newMethod();
</script>
And please not var MODULE ={}, if this is not initialized with {} then it give cannot set property.
I know i am late to the party but as you see there is no satisfying answer available to the question so i am providing my own.
In your case when you write
var Person = new Object();
you are creating an instance of Object type.
You can add a property using prototype property to the Object, not to the instance of Object.which you can use by the instance laterly.
so you can define like
Object.prototype.saySomething = function ()
{
console.log("hello");
};
now you can call it like this.
Person.saySomething();
You can check here.
var Person = function(name) {
this.canTalk = true;
this.name = name;
};
Person.prototype.greet = function() {
if (this.canTalk) {
console.log('Hi, I am ' + this.name);
}
};
bob = new Person('bob');
bob.greet();
I have a namespace generator that looks like this: (As a requirement, it also needs to have prototype objects extra and default).
function generateNamespace(staticMethods, prototypeMethods){
var namespace = function(){}; //create namespace
/**add staticMehods and prototypeMethods to namespace*/
extend(namespace, staticMethods); //extend function from NojeJS
extend(namespace.prototype, prototypeMethods);
//create extra and default objects.
namespace.prototype.default = namespace.prototype.default || {};
namespace.prototype.extra = namespace.prototype.extra || {};
return namespace;
}
The idea is to generate a namespace like this:
var protObj = {id: function(){
console.log("id");
}
}
var myNameSpace = generateNamespace({}, protObj);
When I instantiate:
var instanceOfmyNameSpace = new myNameSpace();
the result contains the functions id, and the objects default, and extra.
But if I run:
var instance2 = new myNameSpace({test: "foo"});
Then: assert.equal(instance2, instanceOfmyNameSpace) \\=true
so that means(?) that the given object just gets ignored.
What do I have to do to merge that object with the default one, for example? The perfect input/output would be:
//input
var instance2 = new myNameSpace({test: "foo"});
//output
console.log(instance2.default.test) \\-> "foo"
UPDATE, ANSWER
All I needed to do was create the namespace as a constructor, and then add staticMethods and prototypeMethods to it:
var extend = require('util')._extend;
function generateNamespace(staticMethods, prototypeMethods){
var namespace = function(defaults, extras){
this.default = extend({}, this.constructor.default, defaults);
this.extra = extend({}, this.constructor.extra, extras);
}
extend(namespace, staticMethods);
extend(namespace.prototype, prototypeMethods);
return namespace;
}
Your code doesn't show how you are copying prototypeMethods or even staticMethods to namespace which makes answering the question hard. I typically use a copy function to do operations like these. It would work for both the static and prototype methods.
Here is the mixin/copy function:
var mixin = function (obj, mixins) {
var keys = Object.keys(mixins);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
obj[key] = mixins[key];
}
};
And you would use it like:
function generateNamespace(staticMethods, prototypeMethods){
var namespace = function () {}; //create namespace
// copy staticMethods to namespace
mixin(namespace, staticMethods);
// copy prototype members
mixin(namespace.prototype, prototypeMethods);
//create extra and default objects.
namespace.prototype.default = namespace.prototype.default || {};
namespace.prototype.extra = namespace.prototype.extra || {};
return namespace;
}
Also note that with the line: namespace = function(){}; //create namespace you need to add a var as I did when declaring namespace otherwise the variable is made global and could exhibit unexpected behaviors.
Out the following two ways, which format for defining object is good considering performance and usage:
//Object created with public members defined using this.
var object1 = function () {
var private_i = null;
this.public_j = null;
//public function
this.public_func = function () {
}
}
OR
//Object created with public members defined using return patterns.
var object2 = function () {
var private_i = null,
public_j = null,
//private function will be exposed from return statement.
_public_func = function () {
};
return {
public_func : _public_func
};
}
The difference between the two relates to inheritance and usage. Your object2 always creates objects directly backed by Object.prototype and doesn't require use of the new keyword; your object1 creates object backed by object1.prototype (which is in turn backed by Object.prototype) and does require use of new.
Neither is really "better" in any objective way, they are just two different ways of using JavaScript, which will have fundamentally the same performance. The first one is much more common, the second one is advocated by a small but vocal minority within the JavaScript community.
The object1 example is more typically written like this:
function Object1() {
var private_i = null;
this.public_j = null;
//public function
this.public_func = function () {
};
}
Note that the first letter in such functions is capitalized (by overwhelming convention).
The prototype thing comes into it if you're going to have functions that don't need access to private_i: You could put those on the object that will be assigned to new objects created via new Object1 like so:
function Object1() {
var private_i = null;
this.public_j = null;
//public function
this.public_func = function () {
};
}
Object1.prototype.someOtherFunction = function() {
// Doesn't use `private_i`
};
You can also use prototypes with your object2, like so:
//Object created with public members defined using return patterns.
var object2Prototype = {
someOtherFunction: function() {
// Doesn't need private_i
};
};
var object2 = function () {
var private_i = null,
public_j = null,
//private function will be exposed from return statement.
_public_func = function () {
};
var obj = Object.create(object2Prototype);
obj.public_func = _public_func;
return obj;
};
Is there a name for describing the different ways you can define an object in Javascript?
There is this method which is more 'class-like' :
function MyObject() {
this.aMethod= new function(){
};
this.anotherMethod = new function(){
};
}
And this other technique which is more 'dynamic'.
MyObject = new Object();
MyObject.aMethod= new function(){
};
MyObject.anotherMethod = new function(){
};
I have been using both of these techniques in various ways, and i understand the benefits of each, but for the life of me, I don't have any idea how to call these two techniques when discussing this with colleauges.
Do these techniques have names?
In the first case MyObject is a constructor function, since it is supposed to be called with new:
var obj = new MyObject();
In the second case, MyObject is just an object and you assign properties to it. It does not have a special name.
Note that in both cases MyObject has different values. MyObject in the second case is equivalent to obj.
A third way is to use an object initilizer or "object literal":
var obj = {
aMethod: function(){},
anotherMethod: function(){}
};
Your first example is an Object Constructor, while the second is simply adding public methods as properties to an object. As a side note, for an even more "class-like" behavior take a look at the module pattern:
var MyObject = (function() {
var privateStaticVariable = 0;
var my = function() {
var self = this;
var privateInstanceVariable = 0;
function privateInstanceMethod() {
}
self.publicInstanceVariable = 0;
self.publicInstanceMethod = function() {
};
};
function privateStaticMethod() {
};
return my;
});
I've been learning more about javascript's prototypal inheritance. I know there is a somewhat fierce debate on whether to extend native objects and I'd like to side step that whole debate entirely in this question.
Is it possible to extend only descendent object in javascript?
To extend all objects I can do this:
Object.prototype.size = function(){
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
But the problem is that It extends all objects. What I'd like to do is have this:
var MyNameSpace = function(){
};
MyNameSpace.Object.prototype.size = function(){
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
That way I would only be extending the native objects in the scope of my global object.
any suggestions would be great thanks
Update:
In response to a few comments I'm adding more code to clarify what I'm trying to do.
I think i may have not phrased my question correctly, or maybe my thinking is incorrect, but what i'd like to be able to do is this:
var my = new MyNameSpace();
var my.name = {firstName : 'Hello', lastName : 'World'};
var nameCount = my.name.size(); // 2
the code you provided will allow me to get the size of each MyNameSpace object I create, but not the object literals that are properties of the MyNameSpace object
You could use "pseudo-classical" inheritance style to achieve it:
var MyNameSpace = function() {
this.v1 = null;
this.v2 = null;
}
MyNameSpace.prototype.size = function() {
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
var my = new MyNameSpace(); // create new object based on MyNameSpace
my.size(); // length would be 2
What you define on a function object's prototype would be inherited by all the function objects created via new operator.
Updated code, according to your added requirements,
var obj = {};
var MyNameSpace = function(props) {
for(var name in props) {
this[name] = props[name];
}
}
MyNameSpace.prototype.size = function() {
var length = 0;
for(var i in this){
if(this.hasOwnProperty(i)){
length++;
}
}
return this;
}
obj.name = new MyNameSpace({firstName : 'Hello', lastName : 'World'});
obj.name.size(); // length would be 2
In your code
var my = new MyNameSpace();
var my.name = {firstName : 'Hello', lastName : 'World'};
var nameCount = my.name.size(); // 2
my.name is obviously traversable from my, but the opposite is not true. That means that properties of my cannot be accessed from my.name, and my is nowhere to be found in the prototype chain of my.name. If you don't want to inherit directly from MyNameSpace you have to explicitly "hang on" whatever functions you would like to inherit.
You could do
my.name.size = my.size;
alternatively (without having to instantiate MyNameSpace):
my.name.size = MyNameSpace.prototype.size;
if you have only few functions to "inherit". Or you could define an inherit function in MyNameSpace as follows:
MyNameSpace.prototype.addToNameSpace = function(obj) {
obj.size = this.size;
// obj.propertyI = this.propertyI, etc.
}
Note that I don't use for..in here as that would add the addToNameSpace function as well.
Hope this helps