I am testing what happens when I declare variables/methods with var, this, and global, and am wondering what is the best approach. I have the following code:
myApp.ConfirmationWindow = function (temptype) {
var _type = temptype;
this.type = temptype;
type2 = temptype;
this.getType = function () {
return _type;
}
this.showConfirmationWindow = function (message) {
var a = _type; //valid
var b = this.type; //valid
var c = type2; // valid
var d = this.getType(); // valid
this.showWindow(message);
showWindow2(message);
showWindow3(message);
}
this.showWindow = function (message) {
var a = _type; //valid
var b = this.type; //valid
var c = type2; // valid
var d = this.getType(); // valid
}
showWindow2 = function (message) {
var a = _type; //valid
var b = this.type; //invalid
var c = type2; // valid
var d = this.getType(); // invalid
}
var showWindow3 = function (message) {
var a = _type; //valid
var b = this.type; //invalid
var c = type2; // valid
var d = this.getType(); // invalid
}
};
Usage:
myApp.ConfirmationWindow1 = new myApp.ConfirmationWindow(1);
myApp.ConfirmationWindow1.showConfirmationWindow('Are you sure?');
The goal is to have the type variable and the showWindow function private. As you can see from my example, there are a lot of ways to achieve this. What is the recommended way?
I would suggest to use the module reveal pattern, where you keep the private variable in a closure. Here below a generic example. You can read more about the revealing pattern here:
let myVar = true;
let module = (function() {
// these are private variables (in a closure)
let _privateVariable = 'private',
_privateFunction = function() {
alert(_privateVariable);
};
let _publicVariable = 'public',
_publicFunctionGet = function() {
alert(_publicVariable);
},
_publicFunctionSet = function(value) {
_publicVariable = value;
};
// provide public functions to set the private variables
return {
publicFunctionSet: _publicFunctionSet,
publicFunctionGet: _publicFunctionGet
};
})();
module.publicFunctionSet('new public');
module.publicFunctionGet();
alert(myVar); // available to other part of your code
You can hide your private code using the var pattern in your example. To expose your private variables you use your instance functions. If you make them global or members of the function then they are public.
myApp.ConfirmationWindow = function (temptype) {
var _type = temptype;
this.getType = function () {
return _type;
}
var showWindow = function (message) {
var d = _type
}
this.showConfirmationWindow = function (message) {
showWindow(message);
}
};
Related
I want to reuse the function sayMyName but with different variables. Please let me know if I'm structuring this the wrong way and what is the best practice what what I'm trying to do.
var sayMyName = function(myName) {
console.log(myName)
};
var name1 = function() {
// myName should not be a global variable
// because there may be more variables/functions
// that I'd want to closed inside sayMyName().
// Declaring all of them to the global scope is not ideal.
var myName = 'Walter';
sayMyName();
// I don't want to pass in myName as argument like this:
// sayMyName(myName);
// I want myName to be implicitly included in sayMyName()
// I want to pass in everything that is declared in name1 to sayMyName() implicitly.
};
var name2 = function() {
var myName = 'White';
sayMyName();
}
name1(); // should give me 'Walter'
name2(); // should give me 'White'
I'm not sure why you specifically want a closure, but by looking at your example it seems that a bind would be more appropriate than a closure.
var sayMyName = function(myName) {
console.log(myName)
};
var name1 = sayMyName.bind(undefined, 'Walter');
var name2 = sayMyName.bind(undefined, 'White');
name1(); // log 'Walter'
name2(); // log 'White'
Move your variable myName to the outermost scope:
var myName;
var sayMyName = function() {
console.log(myName)
};
var name1 = function() {
myName = 'Walter';
sayMyName();
};
var name2 = function() {
myName = 'White';
sayMyName();
}
name1(); // should give me 'Walter'
name2(); // should give me 'White'
Update: Thinking about it, if you're willing to use the non-standard, Error.stack attribute, are willing to use named functions, and are willing to use a naming convention, you could hackishly achieve your goal:
function sayMyName() {
try {
throw new Error();
}
catch (e) {
if (e.stack) { // non-standard attribute
var reNames = /^\s*at myNameIs([A-Z][^(\s]*)\s*\(/mg;
reNames.lastIndex = 0;
var buffer = [];
for (var match = reNames.exec(e.stack); null !== match; match = reNames.exec(e.stack)) {
buffer.push(match[1]);
}
console.log(buffer.join(" "));
}
}
}
function myNameIsWalter() {
sayMyName();
}
function myNameIsWhite() {
myNameIsWalter();
};
myNameIsWalter(); // "Walter"
myNameIsWhite(); // "Walter White"
... and if you're willing to use eval (bad !!!), then you could do fancier things like the following:
var sayMyName = function () {
try {
throw new Error();
}
catch (e) {
if (e.stack) { // non-standard attribute
var reNames = /^\s*at ([_a-zA-Z][_a-zA-Z0-9]+(\.[_a-zA-Z][_a-zA-Z0-9]+)*)/mg;
reNames.lastIndex = 0;
var reMyName = /\bmyName\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
var identifier, definition, match, myName, buffer = [];
while (null !== (match = reNames.exec(e.stack))) {
try {
identifier = match[1];
if ("sayMyName" !== identifier) {
definition = eval(match[1] + '.toString()');
if (/\bsayMyName\(\)/.test(definition)) {
reMyName.lastIndex = 0;
buffer.length = 0;
while (null !== (myName = reMyName.exec(definition))) {
buffer.push(myName[1]);
}
console.log(buffer.join(" "));
}
}
}
catch (_) {
// continue
}
}
}
}
};
function name1() {
var myName = "Walter";
sayMyName();
}
function name2() {
var myName;
myName = "Walter";
myName = "White";
sayMyName();
}
name1(); // "Walter"
name2(); // "Walter White"
You could even use the non-standard, Function.caller attribute, which is probably the cleanest approach (if it works in your browser -- it's non-standard for a reason):
function sayMyName() {
var reMyName = /\bmyName\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
var definition, buffer = [];
for (var caller = sayMyName.caller; caller; caller = caller.caller) {
definition = caller.toString();
if (/\bsayMyName\(\)/.test(definition)) {
reMyName.lastIndex = 0;
buffer.length = 0;
while (null !== (myName = reMyName.exec(definition))) {
buffer.push(myName[1]);
}
console.log(buffer.join(" "));
}
}
};
function name1() {
var myName = "Walter";
sayMyName();
}
function name2() {
var myName;
myName = "Walter";
myName = "White";
sayMyName();
}
name1(); // "Walter"
name2(); // "Walter White"
This is arguably no less code than just passing a parameter, though.
If you want closure then this is example.
function sayMyName(myName){
return function(){
console.log(myName); //myName is available from parent scope
return myName;
}
}
var name1 = sayMyName('Walter');
var name2 = sayMyName('White');
//no console output by now
name1(); //Walter
name2(); //White
//myName is not available in global scope
console.log(myName); //undefined
If I have this code
var node = function(n) {
var name = n;
var children = [];
var finished = false;
var failed = false;
this.getName = function() {
return name
};
this.downloadData = function(obj) {
};
this.getChildren = function() {
return children;
};
this.setChildren = function(c) {
Array.prototype.push.apply(children, c);
};
this.isFinished = function() {
return finished;
};
this.setFinished = function() {
finished = true;
}
this.isFailed = function() {
return failed;
}
this.setFailed = function() {
failed = true;
}
};
How can I convert this into an object like:
var a = new node("a");
var j = JSON.stringify(a);
result
{"name":"a","children":[],"finished":false,"failed":false}
thanks
This could be done by implementing the toJSON function.
If an object being stringified has a property named toJSON whose value
is a function, then the toJSON() method customizes JSON
stringification behavior: instead of the object being serialized, the
value returned by the toJSON() method when called will be serialized.
- Mozilla
eg:
var node = function(n) {
var name = n;
var children = [];
var finished = false;
var failed = false;
this.toJson = function toJson() {
return {"name":name ... };
}
}
You need object properties instead of variables.
So, instead of declaring var name = n;, you would declare this.name = n;. Which would make it look something like
var node = function(n) {
this.name = n;
this.children = [];
this.finished = false;
this.failed = false;
///other functions here
}
I've been toying around with Screeps for a while now and last night I decided to work out some of my behaviors into a class hierarchy by deriving two classes, Miner and Transporter from a Creep main class. However, whenever I do
console.log(_.functions(minerInstance));
I get the exact same function list as when I do
console.log(_.functions(transporterInstance));
Could someone tell me if I'm doing something wrong OR if I'm actually running into a limitation of the environment my code runs in?
This is my code:
////////////////////////////
// Creep.js
var Creep = function(creep, room) {
this.creep = creep;
this.room = room;
this.name = creep.name;
this.id = creep.id;
};
module.exports = Creep;
Creep.prototype = {
tick: function() {
console.log("Base class implementation of tick(), should never happen.");
},
getRole: function() {
return this.creep.memory.role;
}
};
////////////////////////////
// Miner.js
var Creep = require("Creep");
var Miner = function(creep, room) {
this.base = Creep;
this.base(creep, room);
//Creep.call(this, creep, room);
};
module.exports = Miner;
Miner.prototype = Creep.prototype;
Miner.prototype.tick = function() {
var creep = this.creep;
if (creep.memory.activity === undefined || creep.memory.activity === "") {
var target = creep.pos.findNearest(Game.SOURCES_ACTIVE);
this.mine(creep, target);
}
var act = creep.memory.activity;
if (act == "mine") {
var target = this.getTarget(creep);
if (target !== undefined) {
if (creep.energy < creep.energyCapacity) {
creep.moveTo(target);
creep.harvest(target);
} else {
console.log("Write dump to truck code");
/*var trucks = find.transporterInRange(creep, 1);
if (trucks.length) {
creep.moveTo(trucks[0]);
var amount = trucks[0].energyCapacity - trucks[0].energy;
creep.transferEnergy(trucks[0], amount);
}*/
}
}
}
};
Miner.prototype.mine = function(creep, target) {
creep.memory.target = target.id;
creep.memory.activity = "mine";
};
Miner.prototype.getTarget = function(creep) {
return Game.getObjectById(creep.memory.target);
};
////////////////////////////
// Transporter.js
var Creep = require("Creep");
var Transporter = function(creep, room) {
Creep.call(this, creep, room);
};
module.exports = Transporter;
Transporter.prototype = Creep.prototype;
Transporter.prototype.tick = function() {
var creep = this.creep;
if (creep.energy < creep.energyCapacity) {
var miner = this.room.findByRole(creep, "miner");
console.log(miner);
if (miner !== null) {
//console.log(miner[0].name);
//creep.moveTo(miner);
} else
console.log("no miners found");
} else {
console.log("moving to drop");
//var drop = find.nearestEnergyDropOff(creep);
//creep.moveTo(drop);
//creep.transferEnergy(drop);
}
};
With this line...
Miner.prototype = Creep.prototype;
... you tell JS that both prototypes are actually the same object. Hence any update for Miner.prototype will affect Creep.prototype too.
One possible approach is using Object.create when establishing the link between prototypes. Here goes a simplified example:
function Foo(a) {
this.a = a;
}
Foo.prototype.tick = function() { console.log('Foo ticks'); };
Foo.prototype.tock = function() { console.log('Foo tocks'); };
function Bar(a, b) {
this.base = Foo;
this.base(a);
this.b = b;
}
Bar.prototype = Object.create(Foo.prototype);
// as you inherit all the properties, you'll have to reassign a constructor
Bar.prototype.constructor = Bar;
Bar.prototype.tick = function() { console.log('Bar ticks'); };
var f = new Foo(1);
f.tick(); // Foo ticks
f.tock(); // Foo tocks
console.log(f); // Foo { a=1, ... }
var b = new Bar(1, 2);
b.tick(); // Bar ticks
b.tock(); // Foo tocks
console.log(b); // Bar { a=1, b=2, ... }
I found a Module pattern in JS:
<script>
var MODULENAME = (function(my, $) {
my.publicVar = "5";
my.publicFn = function() {};
return my;
}(MODULENAME || {}, jQuery));
</script>
However I cannot perform instantiation. Does the module pattern allow for that?
Instantiantion means basically that you'll run a function using new.
So maybe you're looking for this?
var Some = function (param) {
var somePrivateVar = 'private';
this.somePublicVar = 'public';
this.method = function () {
return param;
};
};
var some = new Some('abla');
console.log(some.method());
// some.somePrivateVar === undefined
// some.somePublicVar === 'public'
In your case MODULENAME is an object (object, not a function) with publicVar and publicFn. It's not meant to be instantiated the same way you wouldn't call new jQuery().
Your module object can contain anything. Perhaps you're looking for including a constructor in it:
var MODULENAME = (function(my, $) {
var privateVar = 10;
my.SomeConstructor = function() {
this.publicVar = 5;
}
my.SomeConstructor.prototype.someMethod = function() {};
my.SomeConstructor.prototype.getPrivate = function() { return 10; };
return my;
}(MODULENAME || {}, jQuery));
var instance = new MODULENAME.SomeConstructor();
instance.publicVar; // 5
instance.privateVar; // undefined
instance.getPrivate(); // 10
You can do this also with prototype Inheritance :
var MyClass = function(name)
{
//sharing name within the whole class
this.name = name;
}
MyClass.prototype.getName = function(){
return this.name;//now name is visible to getName method too
}
MyClass.StaticMethod = function()
{
console.log("Im Static");
// and since is not in prototype chain, this.name is not visible
}
var myclass = new MyClass("Carlos");
console.log(myclass.getName())//print "Carlos"
MyClass.StaticMethod()// print "Im Static"
myclass.StaticMethod() // error
Se all this article
I'm trying to extend an Abstract object.
var Abstract = function() { code = 'Abstract'; };
Abstract.prototype.getCode = function() { return code; };
Abstract.prototype.getC = function() { return c; };
var ItemA = function() { code = 'ItemA'; c = 'a'; };
ItemA.prototype = Object.create(Abstract.prototype);
ItemA.prototype.constructor = ItemA;
var ItemB = function() { code = 'ItemB'; };
ItemB.prototype = Object.create(Abstract.prototype);
ItemB.prototype.constructor = ItemB;
var b = new ItemB();
console.log(b.getCode());
var a = new ItemA();
console.log(b.getCode());
console.log(b.getC());
The result:
ItemB
ItemA
a
Is there any particular reason why I'm getting ItemA's scope in ItemB instance? How can I fix it?
It is because you are using global variables. Fix it by using this keyword:
var Abstract = function() { this.code = 'Abstract'; };
Abstract.prototype.getCode = function() { return this.code; };
Abstract.prototype.getC = function() { return this.c; };
var ItemA = function() { this.code = 'ItemA'; this.c = 'a'; };
ItemA.prototype = Object.create(Abstract.prototype);
ItemA.prototype.constructor = ItemA;
var ItemB = function() { this.code = 'ItemB'; };
ItemB.prototype = Object.create(Abstract.prototype);
ItemB.prototype.constructor = ItemB;
Although in this case ItemB.getC() will return undefined.