Say I have the following code:
function MyObject() {
EventTarget.call(this);
}
MyObject.prototype = new EventTarget();
MyObject.prototype.constructor = MyObject;
MyObject.prototype.foo = someFunction;
MyObject.prototype.bar = someOtherFunction
Is there a neat way to avoid defining MyObject.prototype.something = something in each line.
Do I have to define two objects and merge them? or is there some cleaner way to do the same thing?
Declare the functions inside the controller and you won't have to attach them to the prototype. Is this what you were after?
function EventTarget() {
this.baz = function() {console.log("baz")};
this.foobar = "foobar";
}
function MyObject() {
EventTarget.call(this);
this.foo = function() {console.log("foo")};
this.bar = function() {console.log("bar")};
}
MyObject.prototype = new EventTarget();
MyObject.prototype.constructor = MyObject;
thisObject = new MyObject();
thisObject.foo(); // outputs 'foo'
thisObject.bar(); // outputs 'bar'
thisObject.baz(); // outputs 'baz' via inheritance
console.log(thisObject.foobar); // outputs 'foobar' via inheritance
http://jsfiddle.net/kFUDy/
See the various links mentioned in this answer: Extending an Object in Javascript
Related
I am trying to build a javascript app with a document database that can store and retrieve object data (provided as api) without function members.
Now I have a class which have many properties and some functions as prototype.
Project: function(){
this.a= 'abc';
this.f = function(){
console.log(this.a);
}
}
//object from the databse
p0 = {
a: 'abc';
}
I want to convert a plain object to an object with member function usable.
When I try something like this, it won't work:
// It won't work:
// for it needs a map that have many properties such as writable etc.
var pobj = Object.create(new Project(), p0);
I tried to search this question with different keywords on the internet, but I didn't find one related.
The function you probably want to use is Object.assign.
So you can use Object.create to create an instance of the class (using the prototype), then assign the values from the data onto the new instance and then call the constructor (make sure to not override the values).
function Project() {
if (this.foo === undefined) this.a = 'foobar';
return this;
}
Project.prototype.print = function() {
console.log(this.foo);
};
var data = {
foo: 'bar'
};
var obj = Object.create(Project.prototype); // empty instance
obj = Object.assign(obj, data); // copy data
obj = obj.constructor(); // start constructor
obj.print();
Alternatively you could create a new instance using the new operator and then assign the data.
function Project() {
this.a = 'foobar';
return this;
}
Project.prototype.print = function() {
console.log(this.foo);
};
var data = {
foo: 'bar'
};
var obj = Object.assign(new Project(), data);
obj.print();
Unrelated note
It's usually a good idea to declare public functions that don't require closure outside the function body using class.prototype.functionName = function(){...}
I know that a new method for an object can be declare like so:
var MyObject = function() {return new MyObject.prototype};
MyObject.prototype.exists = function() {alert("The object exists.")};
How can I create many methods as a bunch for MyObject instead of one by one?
I have tried:
MyObject.prototype = {
exists: function() {alert("The object exists.")},
isBorn: function() {alert("The object is born.")},
isDead: function() {alert("The object has left our world.")}
}
Calling MyObject.exists() returns: Uncaught TypeError: MyObject.exists is not a function
What I am trying to do:
I am trying to do something like jQuery does.
jQuery is defined like so:
jQuery = function(selector, context) {included)
return new jQuery.fn.init(selector, context);
}
We don't say var j = new jQuery; when we call it like jQuery("#foo").
Then the files says:
jQuery.fn = jQuery.prototype = {
jquery: version,
constructor: jQuery,
length: 0,
toArray: function() {
return slice.call( this );
}
...
}
Isn't toArray() a method of the jQuery object? Why doesn't it show the same error when I call it.
When the jQuery function is called, you're not creating an instance of jQuery which is why you don't use the new keyword. Instead, you're returning an instance of jQuery.fn.init.
Follow it down and you'll see that the prototype of init being declared:
init.prototype = jQuery.fn;
And the definition for jQuery.fn is:
jQuery.fn = jQuery.prototype = { ... };
Which means that (new jQuery.fn.init(selector, context)) has all the methods from jQuery.prototype.
So, toArray is not a method of the jQuery object, but rather a method on the prototype of the return value from calling jQuery().
You can achieve the same thing in fewer steps by manually assigning the prototype of the return value.
function MyObject() {
var obj = {};
return Object.setPrototypeOf(obj, MyObject.prototype);
}
MyObject.prototype.toArray = function() {};
MyObject().toArray();
You were very close, you just have to create a new instance of the object for it to inherit from its own prototype chain.
var myObj = function () {};
myObj.prototype = {
a: function () { console.log(1) },
b: function () { console.log(2) },
c: function () { console.log(3) }
};
var myObject = new myObj();
myObject.a(); // 1
myObject.b(); // 2
myObject.c(); // 3
The first one is still better because prototype objects have predefined properties (currently only constructor, but later the standard can be extended), and totally overwriting the prototype object will effectively remove those properties. But still it can be shortened like:
function Foo() {}
const p = Foo.prototype;
console.log(Object.getOwnPropertyNames(p));
p.exists = function() { console.log("exists"); };
p.isBorn = function() { console.log("isBorn"); };
(new Foo).exists();
But hey, it's 2016! We have javascript classes in most major browsers (check compatibility at MDN)!
class Foo {
exists() { console.log("exists"); }
isBorn() { console.log("isBorn"); }
}
(new Foo).exists();
this is prototypal model in javascript.
unlike use constructor function with new keyword in this pattern we are using
existing object to create a new object as shown below
var answerprototype = {
name:'ss',
get:function fn1()
{
return "--";
}
}
var lifeanswer = Object.create(answerprototype);
this is how implement private ,public members in javascript using classical pattern
function Restaurant()
{
//private varible
var myPrivateVar = 'aaa';
//public variable
this.myPublicVar = 'bbbb'
//private method
// Only visible inside Restaurant()
var private_stuff = function()
{
return "private metho";
}
//public method
// use_restroom is visible to all
this.use_restroom = function()
{
return "public method"
}
}
//create object
var r1 = new Restaurant();
r1.myPrivateVar //return undefined
r1.myPublicVar //return "bbbb"
r1.private_stuff() //error
r1.use_restroom() //return "public method"
this is how implement static members in javascript using classical pattern
function Shape(shapeName)
{
//instance field
this.ShapeName = shapeName;
//static field
Shape.Count = ++Shape.Count;
//static method
Shape.ShowCount = function()
{
return Shape.Count;
}
}
var shape1 = new Shape("circle");
var shape1 = new Shape("rectangle");
var shape1 = new Shape("Triangle");
Shape.ShowCount(); //return 3
i want to implement static members and private ,public members in javascript using prototypal pattern(not using new keyword with constructor function)
how to do it
In JavaScript, private doesn't mean what you think it means. You have to create a closure which is where you trap your "private" values.
Using a function is the traditional way to create a closure
function makeProto(chainTo) {
const secret = 'foo';
return Object.assign(Object.create(chainTo || null), {
get hello() {return secret;}
});
}
let fizz = makeProto();
fizz.hello; // "foo"
Object.prototype.hasOwnProperty.call(fizz, 'hello'); // true
With ES6, you can use the block-scoped let or const in combination with the function scoped var to achieve something similar
;{
let foo = 'bar';
var obj = {
get baz() {return foo;}
};
}
obj.baz; // "bar"
foo; // ReferenceError
Please remember that as soon as you inherit from one of these objects, all descendant objects will share the same references to these values, not create new ones
I wrote ;{ /* ... */ } so if you try the code in your console it doesn't attempt to interpret this pattern as an Object literal, but instead a code block. In production the initial ; is not necessary.
I have a Mootools class:
var Foo = new Class({
initialize: function(param1, param2) {
// do stuff
}
});
The values to initialize Foo with are in an array:
a = ['value1', 'value2'];
How can I use the values from a to initialize an instance of Foo?
I'd go with extending the proto of the class so it does not care (see Felix' answer).
var Foo = new Class({
initialize: function(param1, param2) {
console.log(param1, param2);
}
});
(function(){
var oldFoo = Foo.prototype.initialize;
Foo.implement({
initialize: function(){
var args = typeOf(arguments[0]) == 'array' ? arguments[0] : arguments;
return oldFoo.apply(this, args);
}
});
}());
new Foo(['one', 'two']); // one two
new Foo('three', 'four'); // three four
It involves less hacking and is probably easier to understand/maintain than creating special constructor abstractions.
if you can, you can even do
var Foo2 = new Class({
Extends: Foo,
initialize: function () {
var args = typeOf(arguments[0]) == 'array' ? arguments[0] : arguments;
this.parent.apply(this, args);
}
});
new Foo2(['one', 'two']);
new Foo2('three', 'four');
Thus, making a very clear abstraction without modifying the parent proto and expectation - and keeping pesky SOLID principles assholes happy :D
There is no direct way of calling a constructor with an array of arguments to be expanded, like you do it with Function.apply.
If you create a new instance of your class with new Foo(), MooTools calls the constructor (initialize) implicitly passing it the arguments you called Foo() with. However, initialize is still present as a method of the instance, so you could simply call it "again" like so:
var myFoo = new Foo();
myFoo.initialize.apply(myFoo, ['value1', 'value2']);
But this is really bad practice, because a constructor is normally not meant to be called twice and chances are that you run into problems.
Another way is to create the instance without letting MooTools call the constructor. First you need a plain instance and then call initialize as a method of the instance. This is rather hackish, but could be realized like this:
var Foo = new Class({
initialize: function(param1, param2) {
this.param1 = param1;
this.param2 = param2;
},
getParams: function() {
console.log(this.param1 + ', ' + this.param2);
}
});
Class.createInstance = function(klass, args) {
klass.$prototyping = true;
var inst = new klass();
klass.$prototyping = false;
inst.initialize.apply(inst, args);
return inst;
}
var myFoo = Class.createInstance(Foo, ['a', 'b']);
// returns "a, b"
myFoo.getParams();
$prototyping is the switch for MooTools to not call the constructor.
Is it possible in javascript to have a variable that is not able to access out side the class's functions, but is able to be accessed by classes that inherit it? I.E:
class1 has protected var x = 4;
class2 inherits class1;
class2.prototype.getVar = function(){return /* parent, uber, super, whatever */ this.x;};
var cl2 = new class2();
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
No. Prototypal inheritance is limited to properties of objects.
Variables within the constructor are only available to other code in that variable scope.
You could probably come up with something like...
function cls1() {
var a = 'foo';
this.some_func = function() {
alert(a);
};
}
function cls2() {
cls1.apply(this, arguments);
var cls1_func = this.some_func;
var b = 'bar'
this.some_func = function() {
cls1_func.apply(this, arguments);
alert(b);
};
}
var x = new cls2;
x.some_func(); // alert "foo" alert "bar"
Or to make it more specific to your pseudo code...
function class1() {
var x = 4;
this.getVar = function() {
return x;
};
}
function class2() {
class1.apply(this, arguments);
var cls1_get_var = this.getVar;
this.getVar = function() {
return cls1_get_var.apply(this, arguments);
};
}
class2.prototype = Object.create( class1.prototype );
var cl2 = new class2;
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
I think you need to use a closure to achieve what your trying to do. Something like this:
Class1 = function() {
var x = 4;
return {
getVar: function() {
return x;
}
}
} ();// executes the function immediately and returns an
//an object with one method - getVar. Through closure this method
//still has access to the variable x
Class2 = function() { };// define a constructor function
Class2.prototype = Class1;//have it inherit from Class1
Cl2 = new Class2();//instantiate a new instance of Class2
console.log(Cl2.x);//this is undefined
console.log(Cl2.getVar());//this outputs 4
This is one of the neat things about javascript in that you can achieve the same things in javascript as you would in a class based language without all the extra key words. Douglas Crockford (always good to consult about javascript) explains prototypal inheritance here
Edit:
Just had a second look at your question.If you want newly created methods in your class to access the variable in the base class then you would have to call the getVar method within your own method.Like such:
Class2 = function() {
this.getVar2 = function() {
return this.getVar();
}
};
console.log(Cl2.getVar2()) //outputs 4