What is the best way to define dependent variables in an object? - javascript

In the Google developers recommendation for optimizing JavaScript code, they mention that the best way to declare/initialize new variables for object is to use the prototype. For instance, instead of:
foo.Bar = function() {
this.prop1_ = 4;
this.prop2_ = true;
this.prop3_ = [];
this.prop4_ = 'blah';
};
Use:
foo.Bar = function() {
this.prop3_ = [];
};
foo.Bar.prototype.prop1_ = 4;
foo.Bar.prototype.prop2_ = true;
foo.Bar.prototype.prop4_ = 'blah';
However, in my case I have a dependency between variables, for instance:
var appv2 = function(){
this.start(this.person, this.car);
};
appv2.prototype.toWhom = 'Mohamed';
appv2.prototype.person = new person(this.toWhom);
appv2.prototype.car = new car();
appv2.prototype.start = function(person, car){
console.log('start for appv2 is called');
person.sayHello('me app v2');
car.brand();
};
new appv2();
Using this.toWhom outside of the main constructor body or a method function of the object will yield undefined. To solve this I could use appv2.prototype.toWhom instead of this.toWhom or I could declare my dependent variables inside of the main constructor body.
But I would like to know what is the best way, in terms of performance, to accomplish this?
Thanks

To reference toWhom while creating person, you can either store the value in a separate variable:
var toWhom = appv2.prototype.toWhom = 'Mohamed';
appv2.prototype.person = new person(toWhom);
Or, reference it from the prototype, as you suspected:
appv2.prototype.person = new person(appv2.prototype.toWhom);
The reason this.toWhom is undefined is because this doesn't refer to an instance of appv2 there.

Related

Javascript Arrays as an object field

I am running into a problem with using an array as a Javascript field.
var Object = function () {
var admins = [];
this.addAdmin = function(admin){
this.admins.push(admin)
}
}
Normally I would expect admin to be pushed into the array admins but instead I get a 'cannot read property 'push' of undefined'.
If I'm not mistaken when I initialized the Object with new Object(), admins = []; should initialize the array. Is this a limitation of Javascript?
Thank you in advance.
var array creates a local variable. It does not create a property on the object.
You need:
this.admins = [];
or
admins.push(admin) /* without this */
In your function admins is a local variable to the function. You need to declare admins as a property on the instance.
function Obj(){
this.admins = [];
}
Obj.prototype.addAdmin = function(admin){
this.admins.push(admin);
}
obj = new Obj();
obj.addAdmin('tester');
Also, because Object is the global base object, don't create functions or objects named Object.
I suspect you've gotten confused (which is easy :-) ) because you've seen code like this:
class Obj {
admins = [];
addAdmin(admin) {
this.admins.push(admin);
}
}
That uses the modern class and class fields syntax to puts an admins property on the object constructed via new Obj. (Note there's no var before admins = [];.) But in your code, you've used the older function-based syntax. Within your function, var admins = []; just creates a local variable, not a property.
I'd suggest that if you want to create constructor functions, using the new class syntax above is the simpler, more powerful way to do that. If you want to use the older syntax, though, other answers have shown how, but for completeness either make admins a property of the object:
let Obj = function() {
this.admins = []; // ***
this.addAdmin = function(admin){
this.admins.push(admin)
};
};
or perhaps with addAdmin on the prototype:
let Obj = function() {
this.admins = []; // ***
};
Obj.prototype.addAdmin = function(admin){
this.admins.push(admin)
};
or use the fact addAdmins closes over the call to Obj, and thus the local admins:
let Obj = function() {
const admins = [];
this.addAdmin = function(admin){
admins.push(admin) // <=== No `this.` here, you want to close over the
// `admins` local
};
};
I am assumming Object is a placeholder, because it is a reserved keyword.
What is happening is, your variable var admins = []; is created locally and can noot be accesed with the this. as a result when you set the value in this.admins.push(admin) the admins there is undefined. you should modify your function to read this way
var Obj = function () {
this.admins = [];
this.addAdmin = function (admin) {
this.admins.push(admin);
};
};
const object = new Obj();
object.addAdmin(1);
you should not omit the this keyword like this(no pun intended) if you plan to new the function. Stick to the code above.
var Obj = function () {
var admins = [];
this.addAdmin = function (admin) {
admins.push(admin);
};
};
const object = new Obj();
console.log(object)

should I use the constructor or the instance when referencing an object's property from another constructor?

While I am writing a constructors' methods like the "runGame" method of the "Game" constructor, if I need to reference a property of the "GameBoard" constructor should I use the name of the constructor, like this:
function Game(){
this.runGame(){
var someProp = GameBoard.otherProp;
}
}
or do I have to create an instance of the constructor object first and then refer to the instance like this.
var newGameBoard = new GameBoard();
function Game(){
this.runGame(){
var someProp = newGameBoard.otherProp;
}
}
If I've understood your question in the right way, what you need is composition and you need to inject associated instances during construction time:
function Game(gameBoard) {
this.gameBoard = gameBoard;
}
Game.prototype = {
runGame: function() {
// You access injected GameBoard through the
// own Game object's property "this.gameBoard"
var someProperty = this.gameBoard.someProperty;
}
};
var gameBoard = new GameBoard();
var game = new Game(gameBoard);
Further reading:
Dependency injection (Wikipedia)
Object composition (Wikipedia)
If every Game has a GameBoard, it should be a property:
function Game(){
this.board=new Board();
}
Game.prototype.runGame=function(){//real inheritance
var someProp = this.board.otherProp;
};
If the GameBoard(s) belong to the Game in your logic, here's how I'd do it
var Game = function(params) {
this.options = params.options; // it could prove useful to instanciate a game using a set of rules
this.gameBoards = params.gameBoards; // Already instanciated gameBoard(s)
this.activeGameBoard = null; // if there are many gameboards it might be a good idea to keep track of the one that's currently active
this.prop = '';
// ... Initialize all the properties you need for your Game object
}
Game.prototype = {
runGame: function(gameBoardIndex) {
this.activeGameBoard = this.gameBoards[index];
this.someProp = this.activeGameBoard.someProp;
}
}
I know I'm assuming a lot of things but I can't help it, it reminds me the only project I worked on that involved games and gameboards :p

performance benefits of using js prototype for structuring large js application

What is the benefit of this:
HB.somepackage = HB.somepackage || {};
HB.somepackage.SomeGoodClass = function(someSelector){
this.someSelector = someSelector;
}
HB.somepackage.SomeGoodClass.prototype.doSomeStuff = function(){
var $obj = $(this.someSelector);
// work your magic with $obj;
};
as opposed to this:
HB.somepackage = HB.somepackage || {};
HB.somepackage.someSelector = "HardCodedValueHere";
HB.somepackage.someOtherSelector = "AnotherHardCodedValueHere";
HB.somepackage.SomeReallyBadClass = function(){};
HB.somepackage.SomeReallyBadClass.prototype.doSomeStuff = function(){};
There's sort of a lot to consider in this question. But to cover the basics, it comes down to prototypal inheritance and lookup.
Your first example:
HB.somepackage = HB.somepackage || {};
HB.somepackage.SomeGoodClass = function(someSelector){
this.someSelector = someSelector;
}
HB.somepackage.SomeGoodClass.prototype.doSomeStuff = function(){
var $obj = $(this.someSelector);
// work your magic with $obj;
};
This makes someSelector a property of SomeGoodClass which can change depending on the callee. If I was to create/call that function binded to a different context, this.someSelector would correspond to that callee context:
var newObject = {someSelector : 'oldSelector'};
HB.somepackage.SomeGoodClass.apply(newObject, 'newSelector');
newObject.someSelector; // 'newSelector'
HB.somepackage.SomeGoodClass.someSelector; // undefined
Codepen: http://codepen.io/anon/pen/yeENXj
So here, you may have thought that inside of the SomeGoodClass this.someSelector would have referred to SomeGoodClass.someSelector but it doesn't.
In your second example:
HB.somepackage = HB.somepackage || {};
HB.somepackage.someSelector = "HardCodedValueHere";
HB.somepackage.someOtherSelector = "AnotherHardCodedValueHere";
HB.somepackage.SomeReallyBadClass = function(){};
HB.somepackage.SomeReallyBadClass.prototype.doSomeStuff = function(){};
someSelector is more or less being used as a type of constant that would need to be referenced inside of other functions of somepackage
Depending on the context of your application and your desired/preferred coding practices one may be desired over the other. In the second example, calling apply() or call() on the SomeGoodClass function would obviously not change the "internal" someSelector attribute of the class but you also wouldn't be able to lookup to the attribute from within the function/object.

Adding scope variable to a constructor

I'm trying to create a class like architecture on javascript but stuck on a point.
Here is the code:
var make = function(args) {
var priv = args.priv,
cons = args.cons,
pub = args.pub;
return function(consParams) {
var priv = priv,
cons = args.cons;
cons.prototype.constructor = cons;
cons.prototype = $.extend({}, pub);
if (!$.isFunction(cons)) {
throw new Hata(100001);
}
return new cons(consParams);
}
};
I'm trying to add the priv variable on the returned function objects's scope and object scope of the cons.prototype but I could not make it;
Here is the usage of the make object:
var myClass = make({
cons: function() {
alert(this.acik);
alert(priv.gizli);
},
pub: {
acik: 'acik'
},
priv: {
gizli: 'gizli'
}
})
myObj = myClass();
PS: Well I have used the outer vars for just to demonstrate what I want to do. I know the private variable syntax of javascript function structure. But I need a solutution for changing (adding private vars) the scope of a function which is going to be used by a "new" (i forgot the pattern name) instantiation pattern.
PS: Please forgive my english...
If you're after the class structure you really should follow the pattern of:
function MyClass(arg){};
Important Note: When ever you set your var names of the inner closure to the same name as it's containing outer closure you no longer have access to the original outer closures vars with the same name.
On the other hand, if you need to access the outer closures vars there is no need to set the inner closures vars with the same name. Just work with the vars as if they're with-in the inner closure.
var make = function(args) {
var priv = args.priv,
cons = args.cons,
pub = args.pub;
return function(consParams) {
var someThing = priv,
sElse = args.cons;
}
};
//
If you need to add a var or private variable to a function object with the name cons: as you've got it below just add it like any other function object.
var myClass = make({
cons: function() {
var myPrivateVariable = 'private';
alert(this.acik);
alert(priv.gizli);
},
pub: {
acik: 'acik'
},
priv: {
gizli: 'gizli'
}
})
myObj = myClass();
If your trying to replicate a class like structure the common approach in Javascript is as follows:
//Constructor
function MyClass(myParam){
this.myParam = myParam
}
MyClass.prototype.myMethod = function(){
alert(this.myParam); //retreives the "class" instance variable myParam
}
//Instantiation
var firstMyClass = new MyClass(7);
firstMyClass.myMethod(); //alerts 7
Note that within the functions you add to the prototype this will be a reference to the MyClass instance. If you would like to make private variables you can checkout this link from Javascript Expert Douglas Crockford: http://javascript.crockford.com/private.html

Is this a safe way to reference objects in JavaScript?

If I were to define two objects myDataStore and myDrawer something like this:
var myDataStore = function(myObjectRef) {
this.myInternalObject = myObjectRef;
};
var myDrawer = function(myObjRef) {
this.myInternalObject = myObjectRef;
};
And if I were to create an object like so:
[[EDIT - Adjusted Object Creation to Ensure 'this' is being mapped to myObject, not the global window object]]
(function(){
var myObject = window.myObject = function(){
this.dataStore = new myDataStore(this);
this.drawer = new myDrawer(this);
}
})();
Then myObject.dataStore.myInternalObject, and myObject.drawer.myInternalObject, would simply be pointers back to the original 'myObject' - not taking up any additional memory in the browser. Yes?
I am interested in implementing techniques like this - as it makes it easy for objects to communicate with each other.
Nope. this refers to whatever is on the left hand side of the . or if there is no left hand side of the . then it's the global object.
So if you did this:
var MyObj = {
"create": function() {
var myObject = {
dataStore = new myDataStore(this);
drawer = new myDrawer(this);
};
}
};
MyObj.create();
this would be MyObj. If you did this:
var myObject = {
dataStore = new myDataStore(this);
drawer = new myDrawer(this);
};
(not in a function) this would be window (assuming this is in a browser).
Yes, your assumption is correct. myInternalObject will be a reference and not a new object. You can test it like this:
var MyDataStore = function(myObjectRef) {
this.myInternalObject = myObjectRef;
};
var data = {
value: "value"
};
var dataStore = new MyDataStore(data);
data.value = "test";
console.log(dataStore.myInternalObject); // logs { value : "test" } instead of { value: "value" }
No. myObject.dataStore.myInternalObject and myObject.drawer.myInternalObject will both point to the global object (mapped to window in browsers), unless you're inside a function already when you declare myObject. In other words, it will be set to whatever this is in the context in which you declare myObject. It won't be myObject itself.

Categories

Resources