How to call a private method via dot notation inside constructor? - javascript

this is the resume: How to call a private method via dot notation inside constructor?:
I know there's a lot of question asking the same... in this particulary I coulnd't find anywhere so I decided to ask.
How receiveAttackFrom() method can be private ?
so if I try this...
soldier1.receiveAttackFrom(soldier2, 50)
would throw an error
var Soldier = function(_name, _life, _damage) {
var name = _name
var life = _life
var damage = _damage
this.getName = function() {return name}
this.getLife = function() {return life}
this.getDamage = function() {return damage}
this.setLife = function(_life) {life = _life}
this.attack = function(_targ) {
_targ.receiveAttackFrom(this, this.getDamage());
}
// how to put this as a private method? :
this.receiveAttackFrom = function(_other, _damage) {
this.setLife( this.getLife() - _damage )
}
}
// MAIN
var soldier1 = new Soldier('jonas', 100, 25);
var soldier2 = new Soldier('mark', 90, 30);
soldier1.attack(soldier2);
// so if I try this...
// soldier1.receiveAttackFrom(soldier2, 50)
// would throw an error

var _self = this;
this.receiveAttackFrom = function(_other, _damage) {
_self.setLife( _self.getLife() - _damage )
}

Define the function at the start of your constructor with var and bind it to this:
var receiveAttackFrom = function (_other, _damage) {
this.setLife( this.getLife() - _damage )
}.bind(this);
Then call it inside the constructor without prefix:
receiveAttackFrom(arg1, arg2);

Related

How do I access a member of the same javascript object?

Say I have the following object definition:
var car = function (engine) {
this.engine = engine;
this.calculateSpeed = function () {
return engine.power * 20;
};
};
the engine object in the calculateSpeed() function refers to the engine object passed in via the constructor and not the car's public engine member(which is the one I want).
If I wanted to change the engine of the car after creating the car object I want the calcuateSpeed() function to reference the new engine.
The Inner function cannot access outer functions variable question is similar to mine. But does not quite cover my use case as the OP is using a local variable and has no constructor.
If you could also explain why this won't work, that would also help a lot:
var car = function (engineInit) {
this.engine = engineInit;
this.calculateSpeed = function () {
return engine.power * 20;
};
};
I know for this simple example I could use this.calculateSpeed = engine.power * 20; but for my real use case, I need a function.
You can actually use this.engine.power.
// Define Car constructor
const Car = function (engineInit) {
this.engine = engineInit;
this.calculateSpeed = function () {
return this.engine.power * 20;
};
};
// Create new car instance
const carInstance = new Car({ power: 100 });
// Log the result of calculateSpeed function
console.log(carInstance.calculateSpeed());
If you want the internal engine to be separate from the engine property visible on the outside of the instantiated Car, you might consider simply having another locally scoped variable, separate from the initial engine parameter, and reassigning it as necessary:
var Car = function(initialEngine) {
this.engine = initialEngine;
let engine = initialEngine;
this.calculateSpeed = function() {
return engine.power * 20;
};
this.changeEngine = function(newEngine) {
engine = newEngine;
}
};
var car = new Car({ power: 20 });
console.log(car.calculateSpeed());
car.changeEngine({ power: 40 });
console.log(car.calculateSpeed());
This question is a duplicate of many other questions on stackoverflow, but here is something to get you started anyway.
By capturing this in another variable:
var car = function(engineInit) {
this.engine = engineInit;
var self = this;
this.calculateSpeed = function () {
return self.engine.power * 20;
};
};
By using bind:
var car = function(engineInit) {
this.engine = engineInit;
this.calculateSpeed = function () {
return this.engine.power * 20;
}.bind(this);
};
By using a function's prototype:
function Car(engine) {
this.engine = engine;
}
Car.prototype.calculateSpeed = function() {
return this.engine.power * 20;
};
var engine = new Engine();
var car = new Car(engine);
var speed = car.calculateSpeed();

How can I make privileged JS methods?

I want to be able to call sub-functions that work with private data. Currently I have this:
var myFunction4 = function() {
this.secret1 = 0;
this.secret2 = 0;
var that = this;
this.iterate1 = function(){
return that.secret1++;
}
this.iterate2 = function(){
return that.secret2++;
}
this.addSecrets = function(){
return that.secret1 + that.secret2;
}
return {
iterate1: this.iterate1,
iterate2: this.iterate2,
addSecrets: this.addSecrets,
}
};
The bad thing about this is that to call one of the methods, I have to do:
myFunction4().iterate1();
Which executes myFunction4() every single time I want to access a method. Not only is this inefficient, but it resets secret1 each time so I can't iterate it. I've tried using the new operator, but that exposes secret1 and secret2, and it messes up the ability to nest functions deeply.
var myFunction3 = function() {
this.secret1 = 0;
this.secret2 = 0;
this.iterate1 = function(){
return this.secret1++;
}
this.iterate2 = function(){
return this.secret2++;
}
this.addSecrets = function(){
return this.secret1 + this.secret2;
}
};
var f3 = new myFunction3();
f3.secret1; // exposes the secret!
See the console logs at the bottom of this JSFiddle for more examples.
How can I have a function with both private and public vars/methods which retain their values and don't need to be called multiple times?
While the other answers are absolutely fine and correct, there is one more issue to consider when emulating OOP behaviour in javascript.
The function execution context issue will bite us hard when we will try to use a public method as a e.g. async. callback.
The magical this will point to a different object then we expect in the OOP world.
Of course there are ways to bind the context but why to worry about this after we define the 'class' in a non OOP js ;)
Here is a simple solution to this: Do not use this. Let the closure refactor this out ;)
var myFunction4 = function() {
// we could inherit here from another 'class' (object)
// by replacing `this` with e.g. `new SuperClass()`
var that = this;
// 'private' variables
var secret1 = 0;
var secret2 = 0;
// 'public' variables
that.somePublicVar = 4;
// 'private' methods
var somePrivateMethod = function(){
secret2 = 77;
that.somePublicVar = 77;
}
// 'public' methods
that.iterate1 = function(){
return secret1++;
}
that.iterate2 = function(){
return secret2++;
}
that.addSecrets = function(){
return secret1 + secret2;
}
return that;
};
var f = new myFunction4();
console.log( f.iterate1() ); // 0
console.log( f.iterate1() ); // 1
console.log( f.secret1 ); //undefined
console.log( f.somePublicVar ); //4
Try that (closures power!):
var myFunction3 = function() {
var secret1 = 0;
var secret2 = 0;
this.iterate1 = function(){
return secret1++;
}
this.iterate2 = function(){
return secret2++;
}
this.addSecrets = function(){
return secret1 + secret2;
}
};
var f3 = new myFunction3();
now only the methods are exposeds
Edited version:
If you don't wanna execute the main function every time you call sub-method, you can change a bit your approach and use the power of IIFE (immediately-invoked function expression)
var myFunction4 = (function() {
var secret1 = 0;
var secret2 = 0;
var iterate1 = function(){
return secret1++;
}
var iterate2 = function(){
return secret2++;
}
var addSecrets = function(){
return secret1 + secret2;
}
return {
iterate1: iterate1,
iterate2: iterate2,
addSecrets: addSecrets
}
}());
Then you can use this:
myFunction4.iterate1();
myFunction4.iterate2();
myFunction4.addSecrets();
Hope this helps you
I generally only use the factory pattern to create objects unless I absolutely need to have the performance benefits of prototypical inheritance.
Using the factory pattern also means you don't have to deal with the ever changing value of this in different contexts.
var factory = function() {
// internal private state
var state = {
secret1: 0,
secret2: 0
}
function iterate1(){
return state.secret1++;
}
function iterate2(){
return state.secret2++;
}
function addSecrets(){
return state.secret1 + state.secret2;
}
function __privateMethod() {
// this is private because it's not on the returned object
}
// this is the public api
return {
iterate1,
iterate2,
addSecrets
}
}
// create a secret module
var secret = factory()
console.log(
secret.iterate1(), // 0
secret.iterate2(), // 0
secret.addSecrets(), // 2
secret.secret1, // undefined
secret.secret2 // undefined
)
// you can even create more with the same factory
var secret2 = factory()
Why don't you try Revealing Module Pattern
var myFunction4 = function() {
var secret1 = 0,
secret2 = 0,
iterate1 = function(){
return secret1++;
},
iterate2 = function(){
return secret2++;
},
addSecrets = function(){
return secret1 + secret2;
};
// public functions and properties
return {
iterate1: iterate1,
iterate2: iterate2,
addSecrets: addSecrets,
}
}();
myFunction4.iterate1(); // is available
myFunction4.secret2; // is private and not available outside of myFunction4
Hope it helps
A basic pattern:
var myFunction = function() {
var that = this;
var secret1 = 0;
var secret2 = 0; // private
this.public1 = 0; // public
this.iterate1 = function(){
return secret1++;
}
this.iterate2 = function(){
return secret2++;
}
this.addSecrets = function() { // public
return privateMethod();
}
var privateMethod = function() { // private
return secret1 + secret2;
}
return this; // return function itself!
};
var myFn = new myFunction();
myFn.public1 // 0
myFn.secret1 // undefined
myFn.addSecrets();
I recommend you to read the excellent Learning JavaScript Design Patterns by Addy Osmani.
What I understand from your explanation as per your second snippet is that you need a sharedPrivate among the instantiated objects. You can not do this with classical object creation patterns like constructor, factory or module. This is possible by taking a private variable under closure in the prototype of the constructor so that it doesn't get reset each time an object is created and at the meantime the instantiated objects are provided with necessary methods to access, modify and share it privately.
function SharedPrivate(){
var secret = 0;
this.constructor.prototype.getSecret = function(){return secret}
this.constructor.prototype.setSecret = function(v){ secret = v;}
this.constructor.prototype.incrementSecret = function(){secret++}
}
var o1 = new SharedPrivate();
var o2 = new SharedPrivate();
console.log(o1.getSecret()); // 0
console.log(o2.getSecret()); // 0
o1.setSecret(7);
console.log(o1.getSecret()); // 7
console.log(o2.getSecret()); // 7
o2.incrementSecret()
console.log(o1.getSecret()); // 8
And another method of getting a similar result would be
function SharedPrivate(){
var secret = 0;
return {getS : function(){return secret},
setS : function(v){secret = v},
incS : function(){secret++}
};
}
sharedProto = SharedPrivate(); // secret is now under closure to be shared
var o1 = Object.create(sharedProto); // sharedProto becomes o1.__proto__
var o2 = Object.create(sharedProto); // sharedProto becomes o2.__proto__
o1.setS(7); // o1 sets secret to 7
console.log(o2.getS()); // when o2 access it secret is still 7
o2.incS(); // o2 increments the secret
console.log(o1.getS()); // o1 can access the incremented value

Simplify the code by using cycle function

I have multiply functions which are using the same cycle code and i'm wondering is it possible to simplify the code by having one cycle function so i could execute the code just by calling wanted function names.
Now:
for(var i=0;i<all;i++){ someFunction(i) }
Need:
cycle(someFunction);
function cycle(name){
for(var i=0;i<all;i++){
name(i);
}
}
I tried to do this by using "window" and i get no error but the function is not executed.
var MyLines = new lineGroup();
MyLines.createLines(); // works
MyLines.addSpeed(); // doesn't work
var lineGroup = function(){
this.lAmount = 5,
this.lines = [],
this.createLines = function (){
for(var i=0,all=this.lAmount;i<all;i++){
this.lines[i] = new line();
}
},
this.addSpeed = function (){
// no error, but it's not executing addSpeed function
// if i write here a normal cycle like in createLines function
// it's working ok
this.linesCycle("addSpeed");
},
this.linesCycle = function(callFunction){
for(var i=0,all=this.lAmount;i<all;i++){
window['lineGroup.lines['+i+'].'+callFunction+'()'];
}
}
}
var line = function (){
this.addSpeed = function (){
console.log("works");
}
}
window['lineGroup.lines['+i+'].'+callFunction+'()'];
literally tries to access a property that starts with lineGroups.lines[0]. Such a property would only exist if you explicitly did window['lineGroups.lines[0]'] = ... which I'm sure you didn't.
There is no need to involve window at all. Just access the object's line property:
this.lines[i][callFunction]();
i get no error but the function is not executed.
Accessing a non-existing property doesn't generate errors. Example:
window[';dghfodstf0ap9sdufgpas9df']
This tries to access the property ;dghfodstf0ap9sdufgpas9df, but since it doesn't exist, this will result in undefined. Since nothing is done with the return value, no change can be observed.
Without a name space use:
window["functionName"](arguments);
SO wrap it up and use it thus:
cycle(someFunction);
function cycle(name){
for(var i=0;i<all;i++){
window[name](i);;
}
}
With a namespace, include that:
window["Namespace"]["myfunction"](i);
Note that this is likely a bit of overkill but using a function to make a class object (you can google the makeClass and why it is/could be useful) you can create instances of the object.
// makeClass - By Hubert Kauker (MIT Licensed)
// original by John Resig (MIT Licensed).
function makeClass() {
var isInternal;
return function (args) {
if (this instanceof arguments.callee) {
if (typeof this.init == "function") {
this.init.apply(this, isInternal ? args : arguments);
}
} else {
isInternal = true;
var instance = new arguments.callee(arguments);
isInternal = false;
return instance;
}
};
}
var line = function () {
this.addSpeed = function () {
console.log("works");
};
};
var LineGroup = makeClass();
LineGroup.prototype.init = function (lineNumber) {
this.lAmount = lineNumber?lineNumber:5,
this.lines = [],
this.createLines = function (mything) {
console.log(mything);
var i = 0;
for (; i < this.lAmount; i++) {
this.lines[i] = new line();
}
},
this.addSpeed = function () {
console.log("here");
this.linesCycle("addSpeed");
},
this.linesCycle = function (callFunction) {
console.log("called:" + callFunction);
var i = 0;
for (; i < this.lAmount; i++) {
this.lines[i][callFunction]();
}
};
};
var myLines = LineGroup();
myLines.createLines("createlines");
myLines.addSpeed();
//now add a new instance with 3 "lines"
var newLines = LineGroup(3);
newLines.createLines("createlines2")
console.log("addspeed is a:" + typeof newLines.addSpeed);
console.log("line count"+newLines.lAmount );
newLines.addSpeed();

How to have function call its own function on its creation

I have a function PublicGame which I'd like to be using similar to a class. When I create PublicGame I give it a bunch of methods by setting this.methodName = function. The only thing is that I want to call some of these methods when the PublicGame is created. Right now for instance I do this.judge = this.setJudge(), but I know this wont work where I have it because, setJudge isnt defined yet. Should I put this at the bottom of PublicGame? Is my design totally off?
Code:
'use strict';
// var GameSockets = require(‘GameSockets’);
var Games = {};
var id_counter = 0;
var minPlayers = 3;
var maxPlayers = 6;
function PublicGame (players) {
this._id = id_counter++;
this.players = players;
this.gameSocket = new GameSockets.registerPlayers(this.players, this._id, this.playerDisconnects);
this.judge = this.setJudge();
this.killGame = function() {
delete Games[this._id];
};
// When a player presses leave game
this.playerExits = function(playerToRemove) {
// Delete player from players array
this.players.splice(this.players.indexOf(playerToRemove),1);
// If less than min players
if (this.players.length < minPlayers) this.killGame();
// If less than max players
if (this.players.length < maxPlayers) {
this.needsPlayers = true;
}
gameSockets.kickPlayer(playerToRemove);
};
// When a player disconnects without warning, e.g. closes window
this.playerDisconnects = function(playerToRemove) {
// Delete player from players array
this.players.splice(this.players.indexOf(playerToRemove),1);
// If less than min players
if (this.players.length < minPlayers) this.killGame();
// If less than max players
if (this.players.length < maxPlayers) {
this.needsPlayers = true;
}
};
this.selectJudges = function() {
this.judge = this.players.pop();
this.players = this.players.unshift(this.judge);
};
this.setWinner = function(winner) {
this.winner = winner;
};
Games[this._id] = this;
}
If you define your functions on the prototype than you do not need to "wait" for the functions to be defined because the instance will already have them when the constructor's code is called
function PublicGame (players) {
//...
this.judge = this.setJudge();
}
PublicGame.prototype.killGame = function(){
//...
};
PublicGame.prototype.playerExits = function(playerToRemove){
//...
};
PublicGame.prototype.setJudge = function(){
//do whatever
return whatever;
};
So unless your functions need to access some "private" variable (ie defined within the constructor, not a global variable), or other reason requiring it, define it on the prototype instead of defining it in the constructor and it will be ready to use.
You have to use javascript prototype !
Read the comments in the code sample.
/*
* utils functions
*
* dont take care about that
**/
var el = document.getElementById('dbg');
var jj = function(val,sep){return JSON.stringify(val , null , sep || '')}
var log = function(val){el.innerHTML+='<div><pre>'+val+'</pre></div>'};
var counterId = 0;
/************************************************************************/
// You have to use prototype
// here an example of what you can achieve
// we create a Player 'class'
var Player = function( name ){
this.id = counterId ++; //<-- an attribute
this.name = name; //<-- an attribute
this.setLevel(5);//<-- a method called at 'instanciation'
return this;
};
// a method available at instanciation time
Player.prototype.setLevel = function(level){
this.level = level;
return this;
};
// we create a new Player named Toto
var Toto = new Player('Toto');
log('Toto = ' + jj(Toto));//<-- utility function just to log
// we create a new Player named Jane
var Jane = new Player('Jane');
log('Jane = ' + jj(Jane)); //<-- utility function just to log
// we change the Level of Jane
Jane.setLevel(12);
log('Jane.setLevel(12)');//<-- utility function just to log
log('Jane = ' + jj(Jane));//<-- utility function just to log
<div id='dbg'></div>

javascript failed to set private variables

I have created a class-like structure with a private variable. The code is as follows:
   
var sinan = function(){
var a = {ssss: 1};
return {
get: function(){
return a;
},
set: function(s){
a = {ssss: s}
}
}
}
When I do
sinan().get(); // outputs {ssss: 1}
sinan().set(2);
sinan().get(); // outputs {ssss: 1}
It didn't output {ssss: 2}. Does anyone know what is happening? Thanks.
Since your "class" is not singleton sinan() constructs new instance every time with a.sss being equal to 1.
What you want to do is to create only once instance and use it:
var s = sinan();
console.log( s.get() );
s.set(2);
console.log( s.get() );
Of course you can make sinon singleton too if you want. For example, here is a simple implementation with instance stored in closure:
var sinan = function () {
var instance;
return function () {
if (!instance) {
instance = function() {
var a = {ssss: 1};
return {
get: function () {
return a;
},
set: function (s) {
a.ssss = s
}
}
}();
}
return instance;
};
}();
So in this case sinan() === sinan(), i.e. sinan() returns the same object every time.
Demo: http://jsfiddle.net/r07wgyjt/
Your problem is that each time you call sinan(), a new sinan instance is created, so it's the same as :
var s1 = sinan();
s1.get(); // 1
var s2 = sinan() ;
s2.set(2); // 2
var s3 = sinan();
s3.get(); // 3
You should be doing :
var s1 = sinan();
s1.get(); // 1
s1.set(2); // 2
s1.get(); // 2

Categories

Resources