In this example. I need to update friends list from object function.
var MyClass = function () {
this.friends = [];
this.runtime = {
add: function (name) {
this.friends.push(name);
}
}
};
MyClass.prototype.AddFriend = function (name) {
this.runtime.add(name);
};
MyClass.prototype.GetFriends = function () {
return this.friends;
};
How it's possible?
You could also use the bind() method:
var MyClass = function () {
this.friends = [];
this.runtime = {
add: function (name) {
this.friends.push(name);
}.bind(this)
}
};
MyClass.prototype.AddFriend = function (name) {
this.runtime.add(name);
};
MyClass.prototype.GetFriends = function () {
return this.friends;
};
Read more about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Like I said in the comments, it makes much more sense to use this.friends.push(name), but if you really have to use that odd runtime function, then you need to save a copy of this to a new variable:
var MyClass = function () {
var _this = this;
this.friends = [];
this.runtime = {
add: function (name) {
_this.friends.push(name);
}
}
};
DEMO
Related
Take this code:
var john = new function () {
var init = function () {
alert("John")
};
return {
init: init
};
};
var jane = new function () {
var init = function () {
alert("Jane")
};
return {
init: init
};
};
function callInit(person) {
var fn = new Function(person); // does not work!
fn.init();
}
$(document).ready(function () {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I would like to pass a string to a function - in my example I pass the string "john". Then I need to convert the passed string to the existing function and call init - in my example call john.init()
Is it possible?
Thanks
You can do it by changing your callInit function to:
function callInit(person) {
var fn = window[person];
fn.init();
}
var john = new function () {
var init = function () {
alert("John")
};
return {
init: init
};
};
var jane = new function () {
var init = function () {
alert("Jane")
};
return {
init: init
};
};
function callInit(person) {
var fn = window[person];
fn.init();
}
$(document).ready(function () {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
One way to achieve this would be by placing the data structures you want to access by key in to an object. You can then use the string passed in to your function as an argument to access that object by key, the advantage being that you avoid using global variables, which pollute the window. It would look like this:
let people = {
john: function() {
var init = function() {
console.log("John")
};
return { init: init };
},
jane: function() {
var init = function() {
console.log("Jane")
};
return { init: init };
}
}
function callInit(person) {
var fn = people[person]();
fn.init();
}
$(document).ready(function() {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Note that if you are going to be using a repeated data structure in this manner I would strongly suggest creating a reusable class for each property within the object. That would look something like this:
class Person {
constructor(name) {
this.name = name;
}
greeting() {
console.log(`Hello, my name is ${this.name}`);
}
}
let people = {
john: new Person('John'),
jane: new Person('Jane')
}
function callInit(person) {
var fn = people[person];
fn.greeting();
}
$(document).ready(function() {
callInit("john");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I'm new in programming and I'm learning JavaScript OOP, trying to make a game with tanks. I have some code but it doesn't work properly and I need some help to understand how it works. Please check it and tell me how to solve the problem because I want to add a few more kinds of tanks but before that I need to fix the code.
var Tank = (function () {
function Tank(name) {
this._name = name;
}
Tank.prototype.getWeight = function () { return this._weight; }
Tank.prototype.getName = function () { return this._name; }
return Tank;
}());
var SmallTank = (function () {
this.prototype = Object.create(Tank.prototype);
function SmallTank(name) {
Tank.apply(this._name);
}
SmallTank.prototype._weight = 2;
return SmallTank;
}());
var myTank = new SmallTank("Aleks Tank");
console.log(myTank.getWeight());
It seems that you're just trying to do some kind of inheritance; typically you do this by assigning a parent instance to the prototype of the child.
I think you will want something like this:
var SmallTank = (function () {
function SmallTank(name) {
Tank.call(this, name);
this._weight = 2;
}
SmallTank.prototype = new Tank();
return SmallTank;
}());
Alternatively you can assign Object.create(Tank.prototype).
Here is another way of doing what it looks like you are attempting to do, following the Mozilla guide:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
var Tank = function (name) {
this.name = name;
};
Tank.prototype.getName = function () { return this.name; };
var SmallTank = function (name) {
Tank.call(this, name);
this.weight = 2;
};
SmallTank.prototype = Object.create(Tank.prototype);
SmallTank.prototype.constructor = SmallTank;
SmallTank.prototype.getWeight = function () { return this.weight; };
var myTank = new SmallTank("Aleks Tank");
console.log(myTank.getName());
console.log(myTank.getWeight());
Is it possible to call parent method in JavaScript class but to still have access to prototype methods from parent and child class. Here is code example:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod = function() {
// call baseInitMethod from Base class
}
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
var s = new Specific();
console.log(s.baseMethod());
console.log(s.baseInitMethod());
console.log(s.basePrototypeMethod());
console.log(s.specificMethod());
console.log(s.specificInitMethod());
console.log(s.specificPrototypeMethod());
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class but so that all function calls from above still works. Is that possible?
Your Specific.prototype object should inherit from the Base.prototype object. Currently you're copying over all its properties to the object with this code:
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
But you should actually use Object.create to establish a real prototype chain:
Specific.prototype = Object.create(Base.prototype);
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class
Yes. In your Specific constructor, you first need get Base's baseInitMethod instance method, before you overwrite the property of the instance:
function Specific() {
Base.call(this);
var parentInitMethod = this.baseInitMethod;
this.baseInitMethod = function() {
// call baseInitMethod from Base class:
parentInitMethod.call(this /*, arguments…*/);
}
…
}
so that all function calls from above still works.
I'm not sure what you mean by that exactly. The specificPrototypeMethod will always call the baseInitMethod of the current instance, which would be Specific's overwritten one not the original that was defined in Base.
Here is what you need to do:
var Base = function () {
};
Base.prototype.baseMethod = function () {
return 'baseMethod';
};
Base.prototype.baseInitMethod = function () {
return 'baseInitMethod';
};
Base.prototype.basePrototypeMethod = function () {
return "basePrototypeMethod";
};
var Specific = function () {
Base.apply(this, arguments);
};
Specific.prototype.baseInitMethod = function () {
Base.prototype.baseInitMethod.apply(this,arguments);
};
Specific.prototype.specificMethod = function () {
return 'specificMethod';
};
Specific.prototype.specificInitMethod = function () {
var basePrototypeMethodCallResult = Base.prototype.basePrototypeMethod.apply(this,arguments);
};
You're overwriting the baseInitMethod of Base inside Specific, with Specific's definition, so why would you ever want to call the Base version? If you simply remove the overwrite of the function you should call the Base definition:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod(); // calls the Base definition only
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
One might argue "Why always trying to mimic 'classical' behaviour and fuss with call and apply instead of embracing the prototype delegation pattern instead?"
Here is what I would code :
var Base = {
baseVariable1: "baseValue1",
baseVariable2: "baseValue2",
baseMethod: function () {
return 'baseMethod';
},
baseInitMethod: function () {
return 'baseInitMethod';
}
}
var Specific = Object.create(Base);
Specific.variable1 = "value1";
Specific.variable2 = "value2";
Specific.specificInitMethod = function () {
return 'specificInitMethod' + '-' + this.baseInitMethod();
}
Specific.specificMethod = function () {
return 'specificMethod' + '-' + this.baseInitMethod();
}
var s = Object.create(Specific);
console.log(s.baseInitMethod());
console.log(s.baseVariable1);
console.log(s.baseVariable2);
console.log(s.variable1);
console.log(s.variable2);
console.log(s.baseMethod());
console.log(s.specificInitMethod());
console.log(s.specificMethod());
class Parentable {
get parent() {
return this.__proto__.__proto__;
}
}
class A extends Parentable {
say() {
console.log('Hello from A');
}
}
class B extends A {
say() {
console.log('Im not A, I am B! But A send you a message:');
this.parent.say();
}
}
(new B()).say();
Suppose I have a function proxyThrough like this:
function proxyThrough(parentClass, childObjPropertyName, methodName) {
parentClass.prototype[methodName] = function() {
this[childObjPropertyName][methodName].apply(this[childObjPropertyName], arguments);
};
}
childPropertyName and methodName are both strings, and it looks up the functions by name.
I know that this will not survive minification as a result.
How can I get functions like this to survive minification?
Example
This is what I am doing currently:
var BaseView = require('./BaseView');
var FooView = require('./FooView');
function BarView() {
this._fooView = new FooView();
}
BarView.prototype = Object.create(BaseView.prototype);
BarView.prototype.constructor = BarView;
BarView.prototype.anAction = function() {
this._barView.anAction.apply(this._barView, arguments);
};
BarView.prototype.anotherAction = function() {
this._barView.anotherAction.apply(this._barView, arguments);
};
This is what I would like to do instead:
var BaseView = require('./BaseView');
var FooView = require('./FooView');
function BarView() {
this._fooView = new FooView();
}
BarView.prototype = Object.create(BaseView.prototype);
BarView.prototype.constructor = BarView;
function proxyThrough(parentClass, childObjPropertyName, methodName) {
parentClass.prototype[methodName] = function() {
this[childObjPropertyName][methodName].apply(this[childObjPropertyName], arguments);
};
}
['anAction', 'anotherAction'].forEach(proxyThrough.bind(null, BarView, '_fooView'));
I guess it depends on how the minifier works, but if it renames the same property name consistently, you could use a helper function to get the minified property name:
function minifiedName(obj) {
for (var prop in obj) {
return prop;
}
}
[
minifiedName({anAction: null}),
minifiedName({anotherAction: null})
].forEach(proxyThrough.bind(null, BarView, '_fooView'));
How could I do this?
Class
var Factory = (function() {
var Class = function() {
this.name = 'John';
this.methods = {
get: function(callback) {
callback();
}
};
};
return {
createClass: function() {
return new Class();
}
};
}());
Usage
var MyClass = Factory.createClass();
MyClass.methods.get(function() {
this.name // => returns undenfined
});
Thanks for any help!
You need to save a reference to this in the outer Class function and call call:
var instance = this;
this.methods = {
get: function(callback) {
callback.call(instance);
}
};
var Class = function() {
// Save a reference to this that can be used in local closures.
var me = this;
this.name = 'John';
this.methods = {
get: function(callback) {
// Use 'call()', passing the reference to the 'Class' object
callback.call(me);
}
};
};
#SLaks - The declaration of scope as a Global variable is bad practice.
#Ferdinand Beyer - have you tested if it functions?
The better way will be the scope binding. The Prototype javascript framework produced a nice concept and we can easily implement it like
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
}
}
and then yoou code should have only a single change and it will maintin the scope of your class.
var Factory = (function() {
var Class = function() {
this.name = 'John';
var me = this;
this.methods = {
get: function(callback) {
callback();
}
};
};
return {
createClass: function() {
return new Class();
}
};
}());
var MyClass = Factory.createClass();
MyClass.methods.get(function() {
console.info(this.name) // => returns undenfined
}.bind(MyClass));
I mean only the function call get with .bind(MyClass)