I'm trying to use OOP in Javascript with inheritance, prototyping and callback functions. Would you please have a look at my JSfiddel http://jsfiddle.net/Charissima/5g6GV/.
The first problem is solved already in Javascript OOP - inheritance and prototyping, but unfortunately the callback functions don't work any more.
function Car () {
this.totalDistance = 0;
};
Car.prototype.putTotalDistance = function(distance) {
this.totalDistance = distance;
};
Car.prototype.getTotalDistance = function() {
return this.totalDistance;
};
Car.prototype.drive = function(distance) {
this.totalDistance += distance;
return this.totalDistance;
};
function RaceCar () {};
RaceCar.prototype = new Car();
RaceCar.prototype.parent = Car.prototype;
RaceCar.prototype.drive = function(distance) {
return this.parent.drive.call(this, (distance * 2));
};
var myText;
car = new Car;
raceCar = new RaceCar;
car.putTotalDistance(200);
myText = 'car totalDistance = ' + car.drive(10) + ' - ok<br>';
raceCar.putTotalDistance(200);
myText += 'raceCar totalDistance before drive = ' + raceCar.getTotalDistance() + ' - ok<br>';
myText += 'raceCar totalDistance after drive = ' + raceCar.drive(10) + ' - ok<br><br>';
car.putTotalDistance(0);
raceCar.putTotalDistance(100);
var drivingFunctions = [car.drive, raceCar.drive];
myText += drivingFunctions[0](10) + '<br>';
try {
myText += drivingFunctions[1](100) + '<br>';
}
catch(err) {
myText += err + + '<br>'
}
document.body.innerHTML = myText;
You've put the two functions in an array, so when called, this get changed.
You could use function bind :
var drivingFunctions = [car.drive.bind(car), raceCar.drive.bind(raceCar)];
Here is an example to help you understand:
function Man(name){
this.name = name;
this.getName = function(){
return this.name;
};
}
var man = new Man('toto');
var a = [man.getName];
console.log(a[0]());//undefined
a.name = 'titi';
console.log(a[0]());//titi, because this refers to the array.
Related
I have a two part question. The first is that I tried to replace all of my document.write with innerHTML and now nothing generates on the page correctly. The second part of my question is that I can't figure out the logic on my toggleCurrent function so that I can hide show the currently displayed view. example - if the thumbnail view is visible I want to hide/show or if the full view is visible I want to hide/show that. http://jsfiddle.net/5M3k7/
//Creating generic Object
function Person(name,age,biog,thumb,char,bg,cider) {
this.fullName = name;
this.age = age;
this.biog = biog;
this.thumb = thumb;
this.char = char;
this.bg = bg;
this.cider = cider;
}
//Creating new Objects
var jay = new Person ("Jay Jones",24,"Story","img","guy","bg","Fleet",true);
var jai = new Person ("Jai Janes",23,"Story","img","gal","bg","Sleet",true);
var dan = new Person ("Dan Dones",19,"Story","img","guy","bg","Leet",true);
var den = new Person ("Den Danes",49,"Story","img","guy","bg","Treat",true);
var dun = new Person ("Dun Dunes",20,"Story","img","guy","bg","Meet",true);
var vim = new Person ("Vim Vanes",22,"Story","img","guy","bg","Meat",true);
//Defining arrays
var characters = [jay, jai, dan, den, dun, vim];
//For loop goes though character array and prints it out.
var thumbs = function() {
var full = document.getElementById('full');
var cLength = characters.length;
for (var i = 0; i < cLength; i++){
full.innerHTML = '<div class="wrap"><div class="cont">' + "Name: " + characters[i].fullName + '<br/>' + 'Age: ' + characters[i].age + '<br/>' + 'Cider: ' + characters[i].cider + '</div></div>';
}
return;
};
var full = function() {
var thumb = document.getElementById('fullthumb');
var cLength = characters.length;
for (var i = 0; i < cLength; i++){
thumb.innerHTML = '<div class="fullwrap"><div class="bg"><div class="fullcont">Name: '
+ characters[i].fullName + '<br/> Age:' + characters[i].age + '<br/>Cider:' + characters[i].cider + '<div class="char"></div></div></div></div>';
}
return;
};
//Toggle Function
function toggleMenuDiv() {
var full = document.getElementById('full');
var thumb = document.getElementById('fullthumb');
var butt = document.getElementById('button');
if (full.style.display == 'none') {
full.style.display = 'block';
thumb.style.display = 'none';
butt.innerHTML = 'THUMB VIEW<span class="arrow-e"></span>';
}
else {
full.style.display = 'none';
thumb.style.display = 'block';
butt.innerHTML = 'FULL VIEW<span class="arrow-e"></span>';
}
}
//Toggle Function
function toggleCurrent() {
var chng = document.getElementById('change');
var thumb = document.getElementById('fullthumb');
var full = document.getElementById('full');
while (full.style.display == 'none')
{
if(thumb.style.display == 'block') {
chng.innerHTML = 'HIDE<span class="arrow-n"></span>';
}else{
thumb.style.display = 'none';
chng.innerHTML = 'SHOW<span class="arrow-s"></span>';
}
}
}
Because you keep overriding the last thing entered in.
full.innerHTML = '<div class="wrap"><div class="cont">' + "Name: " + characters[i].fullName + '<br/>' + 'Age: ' + characters[i].age + '<br/>' + 'Cider: ' + characters[i].cider + '</div></div>';
You are need to append to the innerHTML
full.innerHTML = full.innerHTML + '<div class="...
i want to use two string(which i dont know their content) to create two nameSpace.And i dont want to create a new one if the nameSpace exists.
here is my code:
function createNameSpace(nameSpace)
{
var spaceArr = nameSpace.split(".");
var curSpace = window;
//judge if this nameSpace exists.
var i;
for(i in spaceArr)
{
curSpace = curSpace[spaceArr[i]];
if(curSpace)
window.alert("nameSpace1:" + nameSpace + "\ncurSpace do exists:" + curSpace + "\ni:" + i + "\nspaceArr[i]:" + spaceArr[i] + "|");
else
{
curSpace = {};
window.alert("nameSpace1:" + nameSpace + "\ncurSpace not found:" + curSpace + "\ni:" + i + "\nspaceArr[i]:" + spaceArr[i] + "|");
break;
}
}
//now curSpace must have been created.
i++;
//window.alert("nameSpace2:" + nameSpace + "\ni:" + i + "\nspaceArr.length:" + spaceArr.length);
//create the nameSpace
for(;i < spaceArr.length; i++)
{
//window.alert("nameSpace2:" + nameSpace + "\ni:" + i + "\nspaceArr.length:" + spaceArr.length);
if(i == 0)
{
window[spaceArr[i]] = {};
curSpace = window[spaceArr[i]];
}
else
{
//window.alert("nameSpace3:" + nameSpace + "\ncurSpace[spaceArr[i]]:" + curSpace[spaceArr[i]]);
curSpace[spaceArr[i]] = {};
curSpace = curSpace[spaceArr[i]];
}
}
return curSpace;
}
the problem is,if i send"myTest.myNameSpace"and"myTest.monaNameSpace" into this func,it all alert"curSpace not found",which should be "curSpace do exists:" when i send "myTest.monaNameSpace" . i can`t tell where the mistakes are,can someone tell me?
I think your algorithm is a little to complex. I refactored it a little and added a test to it and verified it worked in the console. I have also written this code several times, so i am pretty sure i have hit your requirements
function createNameSpace(nameSpace)
{
var spaceArr = nameSpace.split(".");
var curSpace = window;
//judge if this nameSpace exists.
var i = 0;
for(i = 0;i < spaceArr.length; i++)
{
var next = spaceArr[i];
console.log(curSpace, next);
if(curSpace[next] == undefined)
{
curSpace[next] = {};
curSpace = curSpace[next]
}
else
{
curSpace = curSpace[next];
}
}
return curSpace;
}
createNameSpace("myTest.myNameSpace");
console.log(myTest.myNameSpace);
myTest.myNameSpace.myName = "Leat Hakkor";
createNameSpace("myTest.monaNameSpace");
console.log(myTest.monaNameSpace);
console.log(myTest.myNameSpace.myName);
So, I want to do something like this:
var a = 'a';
var dummy = function() {
// Print out var 'a', from the scope above
console.log('Dummy a: ' + a);
// Print out 'b', from the 'compelled' scope
console.log('Dummy b: ' + b);
}
(function() {
var b = 'otherscope';
// I know apply won't work, I also don't want to merge scopes
dummy.apply(this);
// I want something like this:
dummy.compel(this, [], {b: 'injected!'});
})();
But that won't work.
I don't actually want a function to be able to reach 2 scopes, I DO want to be able to set the 'b' variable used inside the dummy function from the outside.
You can make b a parameter for the function, or a global variable.
var a = 'a';
var dummy = function(b) {
...
}
or
var a = 'a';
var b;
var dummy = function() {
...
}
The first allows you to choose when the dummy function has access to the variable, the second allows it to be accessed everywhere.
So, I found a little faster way to do such a thing:
var C = function(ctx, funcBody){
var newBody = [];
for(var k in ctx){
var i = "var "+k + " = ctx['"+k+"'];";
newBody.push(i);
}
var res = "return function(t){ " +funcBody+ " }";
newBody.push(res);
var F = new Function("ctx", newBody.join('\n'));
return F(ctx);
}
var newFunction = C({"foo":10, "bar":100}, "return foo+bar*t")
newFunction(50);
Use this:
Function.prototype.applyVars = function(scope, params, scope_variables) {
if (scope_variables) {
var variable, defVars = [];
for (variable in scope_variables) {
if (scope_variables.hasOwnProperty(variable)) {
defVars.push(variable + '=scope_variables["' + variable + '"]');
}
}
eval('var ' + defVars.join(',') + ';');
return eval('(' + this + ').apply(scope, params);');
}
return this.apply(scope, params);
}
// Example
function foo(p1) {
document.write('Variable [p1]: ', p1);
document.write('<br />');
document.write('Variable [x]: ', x);
document.write('<br />');
document.write('Variable [y]: ', y);
}
foo.applyVars(this, ['param X'], { x: "1'2\"3", y: false });
Or this:
function callWithVars(fn, scope, params, scope_variables) {
if (scope_variables) {
var variable, defVars = [];
for (variable in scope_variables) {
if (scope_variables.hasOwnProperty(variable)) {
defVars.push(variable + '=scope_variables["' + variable + '"]');
}
}
eval('var ' + defVars.join(',') + ';');
return eval('(' + fn + ').apply(scope, params);');
}
return fn.apply(scope, params);
}
// Example
function foo(p1) {
document.write('Variable [p1]: ', p1);
document.write('<br />');
document.write('Variable [x]: ', x);
document.write('<br />');
document.write('Variable [y]: ', y);
}
callWithVars(foo, this, ['param X'], { x: "1'2\"3", y: false });
the #vasiliy's solution extended to inject any function
function injectScope(ctx, func) {
var newBody = [];
for (var k in ctx) {
var i = " var " + k + " = ctx['" + k + "'];";
newBody.push(i);
}
let res = (func + '').replace(/^(.*?)\)\s*{(.*)$/gms, `return(\n$1){\n${newBody.join('\n')}\n$2)`);
// console.log(res)
let F = new Function("ctx", res);
return F(ctx);
}
function sum(t) {
return foo + bar * t
}
var injectedSum = injectScope({ "foo": 10, "bar": 100 }, sum)
// console.log(injectedSum+'')
console.log(injectedSum(50));
var Animal = function(config) {
config = config || {};
var name = config.name,
numLegs = config.numLegs,
weight = config.weight,
speed = config.speed,
sound = config.sound
return {
getName: function () {
return name;
},
getNumLegs: function () {
return numLegs;
},
getWeight: function () {
return weight;
},
getSpeed: function () {
return speed;
},
getSound: function () {
return sound;
},
run: function(distance, unit) {
unit = unit || 'miles';
return 'The ' + name + ' ran ' + distance + ' ' + unit;
},
speak: function() {
return 'The ' + name + ' says "' + sound + '"';
}
}
};
function DragonFly(config) {
var me = {},
numWings = config.numWings;
me.prototype = new Animal(config);
me.getNumWings = function() {
return numWings;
};
me.fly = function(distance, unit) {
unit = unit || 'miles';
return 'The ' + me.name + ' flew ' + distance + ' ' + unit;
}
return me;
}
var dragonFly = new DragonFly({
numWings: 2,
name: 'DragonFly',
numLegs: 6
});
Okay, coming from a PHP background, I don't understand inheritance in JavaScript one bit and I'd like some help.
Basically, here's what I'd like to be able to do with an instance of the dragonFly object:
dragonFly.getName(); // 'DragonFly'
dragonFly.fly(1, 'mile'); // 'The dragonfly flew 1 mile';
dragonFly.run(1, 'yard'); // 'The dragonfly ran 1 yard';
I'd also like to know how to override methods and call the parent of those overridden methods. What is wrong with my approach? All the examples above return undefined or throw an error. The main reason I went with the object-literal style is so I could make properties private.
the "fastest" way :
var Animal = function(config) {
config = config || {};
var name = config.name,
numLegs = config.numLegs,
weight = config.weight,
speed = config.speed,
sound = config.sound
return {
getName: function () {
return name;
},
getNumLegs: function () {
return numLegs;
},
getWeight: function () {
return weight;
},
getSpeed: function () {
return speed;
},
getSound: function () {
return sound;
},
run: function(distance, unit) {
unit = unit || 'miles';
return 'The ' + name + ' ran ' + distance + ' ' + unit;
},
speak: function() {
return 'The ' + name + ' says "' + sound + '"';
}
}
};
function DragonFly(config) {
var me = new Animal(config);
var numWings = config.numWings;
me.getNumWings = function() {
return numWings;
};
me.fly = function(distance, unit) {
unit = unit || 'miles';
return 'The ' + me.name + ' flew ' + distance + ' ' + unit;
}
return me;
}
var dragonFly = new DragonFly({
numWings: 2,
name: 'DragonFly',
numLegs: 6
});
You are mixing 2 kind of "inheritance" in your script , the "classical" inheritance and the prototypal inheritance , you cant do that unless you want to be in serious trouble. both work , both have their pros and cons. Stick to the "classical" inheritance , or object augmentation since you began with it.
An object literal doesnt have a prototype , functions have prototypes. That's why in my opinion js isnt "really" object oriented , but it can mimic object oriented langages
A good exercice now would be to try using functions and prototypes , though i'm not sure you could create private fields with that.
Edit : the me.name should be me.getName() since name is "private". i think.
I've been programming for over 20 years, but have recently turned to JavaScript. Despite spending hours trawling the web, the penny hasn't yet dropped with the prototype inheritance method.
In the simplified code below, I am trying to inherit the 'name' property from the Synthesizer 'class' to the Roland 'class', but the only way I seem to be able to access it is by using 'Synth2.prototype.name' rather than by 'Synth2.name' (which returns undefined). I would like to get the approach working so that I can use 'Synth2.name', as portability is a design requirement.
I would be very grateful for any assistance.
function Synthesizer(name) {
this.name = name;
}
function Roland(name) {
this.prototype = new Synthesizer(name);
}
Synth1 = new Synthesizer("Analogue");
Synth2 = new Roland("Fantom G6");
document.write(Synth1.name + '<br>');
document.write(Synth2.name + '<br>');
Thanks guys! (Now updated with call to super class)...
function Synthesizer(name) {
this.name = name;
this.rendersound = function () {
document.write("applying envelope to " + this.name + "<br>");
}
}
function Roland(name) {
Synthesizer.call(this, name);
this.prototype = Synthesizer;
this.Synthesizer_rendersound = this.rendersound;
this.rendersound = function () {
document.write("applying differential interpolation to " + this.name + "<br>");
this.Synthesizer_rendersound(this);
}
}
Synth1 = new Synthesizer("Analogue");
Synth2 = new Roland("Fantom G6");
document.write(Synth1.name + '<br>');
document.write(Synth2.name + '<br>');
document.write('<br>');
Synth1.rendersound();
document.write('<br>');
Synth2.rendersound();
document.write('<br>');
document.write('Synth1.prototype ' + Synth1.prototype + '<br>');
document.write('Synth2.prototype ' + Synth2.prototype + '<br>');
document.write('<br>');
document.write('Synth1.constructor ' + Synth1.constructor + '<br>');
document.write('Synth2.constructor ' + Synth2.constructor + '<br>');
You can do this by several way.
For example :
var Synthesizer = function(name){
this.name = name;
}
function Roland(name) {
Synthesizer.call(this, name); // you call the constructor of Synthesizer
// and force Synthesizer's this to be Roland's this
}
function clone(obj){
var ret = {};
for(var i in obj){ ret[i] = obj[i]; }
return ret;
}
Roland.prototype = clone(Synthesizer.prototype); // inheritance of public functions
For Function.prototype.call : https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Call
I believe you have to set the constructor's prototype, like this:
function Synthesizer(name) {
this.name = name;
}
function Roland(name) {
this.name = name;
}
Roland.prototype = new Synthesizer();
Synth1 = new Synthesizer("Analogue");
Synth2 = new Roland("Fantom G6");
document.write(Synth1.name + '<br>');
document.write(Synth2.name + '<br>');