i have recently an interview and the interviewer simply ask me one question and he say me take your time the question is "can you implement dependency injection like angular good program?" i try to do my best but it seem the interview don't like my program so can anyone give me a simple advice how can i implement it like angular?
Thanks
var WelcomeController = function (Greeter) {
document.write(Greeter.greet());
};
var Injector = {
dependencies: {},
process: function(target) {
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var text = target.toString();
var args = text.match(FN_ARGS)[1].split(',');
target.apply(target, this.getDependencies(args));
},
getDependencies: function(arr) {
var self = this;
return arr.map(function(value) {
return self.dependencies[value];
});
},
register: function(name, dependency) {
this.dependencies[name] = dependency;
}
};
var RobotGreeter = {
greet: function() {
return 'Domo Arigato';
}
};
var OtherGreeter = {
greet: function() {
return 'That will do pig.';
}
};
// Randomly register a different greeter to show that WelcomeController is truly dynamic.
Injector.register('Greeter', Math.random() > 0.5 ? RobotGreeter : OtherGreeter);
Injector.process(WelcomeController);
It's easy to make private variables accessed by public methods of a module you're exporting:
var makeAModule = function() {
var _secret = 'Ssh!';
var module = {
tellMeYourSecret: function() {
console.log(_secret);
}
};
return module;
}
// > var m = makeAModule();
// > m.tellMeYourSecret();
// Ssh!
Sometimes I need to define properties with Object.defineProperty that are computed by getters using the value of other private variables. Those have to go on an object, though, so I end up making a private object just to hold them. If I don't store all my private members on that object, it gets confusing to remember which props are on it and which aren't, so I put everything there:
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(priv, 'secretLength', {
get: function() {
return priv._secret.length;
}
});
var module = {
tellMeYourSecret: function() {
console.log(priv._secret);
},
howLongIsYourSecret: function() {
console.log(priv._secretLength);
}
}
return module;
}
// > var m = makeAModule();
// > m.howLongIsYourSecret();
// 4
Is there any way to define a variable (not attached to an object) whose value is computed through a getter? Something like this:
var makeAModule = function() {
var _secret = 'Ssh!';
Object.defineVariable('_secretLength', {
get: function() {
return _secret.length;
}
})
var module = {
tellMeYourSecret: function() {
console.log(_secret);
},
howLongIsYourSecret: function() {
console.log(_secretLength);
}
}
return module;
}
Not directly.
However, you can set it as a property of window, thus making it a global variable. But using global variables is not recommendable, specially if they are secret.
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(window, '_secretLength', {
get: function() {
return priv._secret.length;
}
});
return {
tellMeYourSecret: function() {
return _secret;
},
howLongIsYourSecret: function() {
return _secretLength;
}
};
};
document.body.innerHTML =
"Secret length: " + makeAModule().howLongIsYourSecret();
Alternatively, you can define your getters as properties of an object, and use a with statement. Note that the with statement can't be used in strict mode.
var makeAModule = function() {
var priv = {};
priv._secret = 'Ssh!';
Object.defineProperty(priv, '_secretLength', {
get: function() {
return priv._secret.length;
}
});
with(priv) {
return {
tellMeYourSecret: function() {
return _secret;
},
howLongIsYourSecret: function() {
return _secretLength;
}
};
}
};
document.body.innerHTML =
"Secret length: " + makeAModule().howLongIsYourSecret();
So I am using a function to update my values, but I can't then get them back. I see values don't get updated, but is there any way of saving them as a reference to the return of the function.
function Amphibia(wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
this.speed = 0;
this.mode = mode;
var amphibiaWheel = new PropulsionUnits.Wheel(wheelRadius);
var amphibiaPropeller = new PropulsionUnits.Propeller(finsPerPropeller, propellersSpinDirection);
this.changeMode = function () {
if (mode == "land") {
mode = "water";
}
else if(mode == "water") {
mode = "land";
}
return {
mode: mode
}
}
this.accelerate = function() {
if(this.mode == "water"){
this.speed += amphibiaPropeller.acceleration;
}
else if(this.mode == "land"){
this.speed += 4*amphibiaWheel.acceleration;
}
}
this.changePropellerSpinDirection = function() {
amphibiaPropeller.changeSpinDirection();
}
return {
speed: this.speed,
mode: this.mode,
changeMode: this.changeMode,
accelerate: this.accelerate,
changePropellerSpinDirection: this.changePropellerSpinDirection
}
}
So here I am experiencing problems with changing the mode and the changeMode function expression. Mode in it should refer to this.mode and then I should be able to update the value.
mode and this.mode are not the same. In your functions you are checking/setting values on mode and this.mode, separately.
Either should work fine, as long as you're using one or the other, in the same place, the same way.
Edit
var Amphibia = function (wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
var amphibia = this,
MODES = { LAND : "land", WATER : "water" };
amphibia.getMode = function () { return mode; };
amphibia.setMode = function (val) { mode = val; };
amphibia.changeMode = function () {
amphibia.setMode((mode === MODES.LAND) ? MODES.WATER : MODES.LAND);
};
};
var amphibia = new Amphibia("", "", "", "land");
amphibia.getMode(); // "land"
amphibia.changeMode();
amphibia.getMode(); // "water"
mode is now 100% private, and unique to that instance.
If you don't need it to be, then you can append it to this, if you'd like.
But here's your problem:
var Amphibia = function () {
var amphibia = this,
amphibiaPropeller = new Propeller( );
// mode, getMode, setMode, etc...
amphibia.accelerate = function () {
if (amphibia.getMode() === "water") {
this.speed += amphibiaPropeller.acceleration;
}
};
};
var amphibia = new Amphibia();
var bob = { speed : 0 };
bob.accelerate = amphibia.accelerate;
bob.accelerate();
// if amphibia.mode === "water", bob.speed += amphibiaPropeller.acceleration
bob.speed; // === amphibiaPropeller.acceleration
setTimeout(amphibia.accelerate, 10); // call amphibia.accelerate in ~10ms
// if amphibia.mode === "water", window.speed += amphibiaPropeller.acceleration
window.speed; // === amphibiaPropeller.acceleration
Be consistent in how you refer to things.
Don't mix self and this, unless you intend to get those side-effects...
And unless you have a very, very good reason to do so (like you're building a framework/engine, not the modules/classes of the game/simulation which use the engine; ie: the difference between building jQuery and building something with jQuery), then you should probably avoid doing it.
If you have closure ("private") state that you want to expose to the outside world, all you need is a function that returns that value, and/or one that sets it.
All of a sudden, the differences between self and this and what is which, when, all go away, as long as you are consistent with how you use them, and you know what the value of this is going to be, every time you call the method.
Notice I'm not returning anything...
When I use new, the value of this (amphibia/self) gets returned by default.
If you want to use private values, and return a "Revealing Module" (which is what I typically prefer), then you can simply do this:
var Amphibia = function (mode) {
var getMode = function () { return mode; },
setMode = function (val) { mode = val; },
changeMode = function () {
setMode( mode === "water" ? "land" : "water" );
};
return {
getMode : getMode,
setMode : setMode,
changeMode : changeMode
};
};
var amphibia = new Amphibia("water");
// `new` won't do any harm, but you can also not use it,
// without it saving everything to `window`
amphibia.getMode(); // "water"
amphibia.changeMode();
amphibia.getMode(); // "land"
Or, maybe if you want that to look a little more like a module/component...
return {
mode : { get : getMode, set : setMode, switch : changeMode }
};
var amphibia = Amphibia("land");
amphibia.mode.get(); // "land"
amphibia.mode.switch();
amphibia.mode.get(); // "water"
var bob = { };
bob.switchAmphibiaMode = amphibia.mode.switch;
bob.switchAmphibiaMode();
amphibia.mode.get(); // "land"
setTimeout(amphibia.mode.switch, 10);
setTimeout(function () { console.log(amphibia.mode.get()); }, 20);
// 10ms amphibia.mode.switch();
// 20ms console.log(amphibia.mode.get());
// > "water"
...or whatever other structure you'd like.
You don't need a this at all.
But this is something to be very, very careful with in JavaScript, because the meaning of this changes every time you call a function, and if half of the code uses this and half uses self, you're bound for some surprises.
I managed to find the answer myself! :) So basicly this in the function constructor refers to Amphibia and this in the this.changeMode function expression refers to object window. Therefore we can define a variable self = this; in the constructor, so we can refer to the same thing in the function expression, as in the function. I explained it a bit awful, but here is my fixed code ;)
function Amphibia(wheelRadius, finsPerPropeller, propellersSpinDirection, mode) {
this.speed = 0;
var self = this;
self.mode = mode;
var amphibiaWheel = new PropulsionUnits.Wheel(wheelRadius);
var amphibiaPropeller = new PropulsionUnits.Propeller(finsPerPropeller, propellersSpinDirection);
this.changeMode = function () {
if (self.mode == "land") {
self.mode = "water";
}
else if(self.mode == "water") {
self.mode = "land";
}
}
this.accelerate = function() {
if(self.mode == "water"){
this.speed += amphibiaPropeller.acceleration;
}
else if(self.mode == "land"){
this.speed += 4*amphibiaWheel.acceleration;
}
}
this.changePropellerSpinDirection = function() {
amphibiaPropeller.changeSpinDirection();
}
return {
speed: this.speed,
mode: this.mode,
changeMode: self.changeMode,
accelerate: this.accelerate,
changePropellerSpinDirection: this.changePropellerSpinDirection
}
}
I have following pattern
BASE = function () {
var that = {};
var number = 10;
that.showNumber = function(){
that.alertNumber();
}
that.alertNumber = function () {
alert(number);
};
return that;
};
CHILD = function () {
var that = Object.create(BASE());
var secondNumber = 20;
// Override base function
that.alertNumber = function () {
alert(secondNumber);
};
return that;
};
var ch = CHILD();
ch.showNumber();
Can you tell me how can I adjust my module pattern inspired by Douglas CrockFord to fully override alerNumber function? So far showNumber function displays 10 instead of 20.
Thank you all in advanced
JSFiddle with code is here
You could change
that.showNumber = function(){
that.alertNumber();
}
to
that.showNumber = function(){
this.alertNumber();
}
But I'm not sure I see why you don't simply use the prototype-base inheritance model.
Unsure if I've phrased this correctly, but in the callback how do I reference the controls property of the base class?
This has been bugging me for some time and I usually work around it, but I'd be grateful if anybody can enlighten me on how I should do this properly.
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
this.init(args.controls);
$(this.controls.DropDown).change(function() {
$(this.controls.PlaceHolder).toggle();
});
}
}
};
Much Obliged,
Paul
Use the power of closures:
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
var self = this;
this.init(args.controls);
$(this.controls.DropDown).change(function() {
$(self.controls.PlaceHolder).toggle();
});
}
}
};
Although closures are preferred, you could also use jquery bind to pass an object along:
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
this.init(args.controls);
$(this.controls.DropDown).bind('change', {controls: this.controls}, function(event) {
$(event.data.controls.PlaceHolder).toggle();
});
}
}
};
You need to leverage closures here.
var base = function() {
var controls = {};
return {
init: function(c) {
this.controls = c
},
foo: function(args) {
this.init(args.controls);
$(this.controls.DropDown).change(function(controls) {
return function(){
$(controls.PlaceHolder).toggle();
}
}(this.controls));
}
}
};