I'm trying to get this:
a = new Foo(name); // a is function
a(); // returns a result
a.set(); // returns another result
I've implemented above like that:
function Foo (name) = {
val = name;
ret = function () { return val; }
ret.set = function (v) { return val = v; }
return ret;
}
Then, for multiple instances of Foo I'd like not to create method 'set', but share it through prototype property. However, all experiments I did have no effect. It works only on objects, not on functions. Even the code below doesn't work:
foo = function () { return 'a'; }
foo.foo = function () { return 'foo'; }
foo.prototype.bar = function () { return 'bar'; }
foo(); // a
foo.foo(); // foo
foo.bar(); // Uncaught TypeError: Object function () { return 'a'; } has no method 'bar'
Unfortunately there is no way to add a property to only some functions via the prototype chain. Functions have one object in their prototype chain, which is Function.prototype. There is no way to create functions which have other [[Prototype]]s.
The closest you can come to what you want are these two examples:
Your solution
function Foo (name) = {
val = name;
ret = function () { return val; }
ret.set = function (v) { return val = v; }
return ret;
}
Changing Function.prototype
Function.prototype.set = function (v) { return this.val = v; };
function Foo (name){
ret = function () { return this.val; }
ret.val = name;
return ret;
}
var f = new Foo('myfunc');
f.set('myval');
console.log(f.val);
I would strongly recommend the first solution, because in the second one, every function shares the set property/method. Changing predefined Prototypes is usually frowned upon unless it's to port functionality from newer editions of the language.
In your last example foo does not have the function bar, only it's prototype does.
Therefore only a foo object would have the function bar
So you could do this:
foo = function () { return 'a'; }
foo.foo = function () { return 'foo'; }
foo.prototype.bar = function () { return 'bar'; }
var f = new foo(); // [object]
f.foo(); // TypeError: Object [object Object] has no method 'foo'
f.bar(); // bar
Try this:
foo = function (name){
this.name = name;
}
foo.prototype.set = function(name){ return this.name = name; }
var f = new foo('yourName');
alert(f.name);
f.set('yourNameEdited');
alert(f.name);
Here's DEMO
Related
Let's say I have classes A and B. Class B has a member which is an instance of class A, let's call it this.a.
When inside B's methods I try to access A's methods as this.a.<methodName>, I get the following error:
TypeError: this.a is undefined
Here is my code:
function A (name) {
this.name = name;
}
A.prototype.foo = function () {
this.name = this.name.toUpperCase();
};
A.prototype.bar = function () {
this.name = this.name.toLowerCase();
};
function B () {
this.a = new A('Hello, World!');
}
B.prototype.methodsOfA = {
foo: this.a.foo, // here is the problem
bar: this.a.bar //
};
B.prototype.executeMethodOfA = function (methodName) {
this.methodsOfA[methodName]();
//the following works if I delete B.prototype.methodsOfA:
//if (methodName.toLowerCase() === 'foo') this.a.foo();
//else if (methodName.toLowerCase() === 'bar') this.a.bar(); //
};
b = new B();
console.log(b.a.name);
b.executeMethodOfA('foo');
console.log(b.a.name);
b.executeMethodOfA('bar');
console.log(b.a.name);
Instead, if I use the following definition:
B.prototype.methodsOfA = {
foo: A.prototype.foo,
bar: A.prototype.bar
};
I get the following error:
TypeError: this.name is undefined
(probably because this in this case is b and a B object has no name property.)
So, how can I access this.a.<methodName> from inside B?
Note: This is a simplified version of a larger problem. I know that what I asked could be solved with class/prototype inheritance, but ideally I would like B not to inherit from A.
My spidey sense says there's a better way to solve this problem, but here is some working code for now..
function A (name) {
this.name = name;
}
A.prototype.foo = function () {
this.name = this.name.toUpperCase();
};
A.prototype.bar = function () {
this.name = this.name.toLowerCase();
};
function B () {
this.a = new A('Hello, World!');
}
B.prototype.methodsOfA = function (methodName) {
var methods = {
foo: this.a.foo.bind(this.a),
bar: this.a.bar.bind(this.a),
}
return methods[methodName];
};
B.prototype.executeMethodOfA = function (methodName) {
this.methodsOfA(methodName)();
};
b = new B();
console.log(b.a.name);
b.executeMethodOfA('foo');
console.log(b.a.name);
b.executeMethodOfA('bar');
console.log(b.a.name);
You had two problems:
this in the context of an object didn't refer to the this you were thinking of. It was referring to the window, because methodsOfA, as a plain object, won't be injected with this. I changed it to a proper method, and now this is the this you want.
You need to bind the A methods to your local instance of A itself. This is because methods are only given the expected this pointer when invoked in the style a.foo(). Assigning a.foo to another name and invoking it, as you're doing, will lose the this context. You can force the correct context with bind() as you see above.
The way you referning this is wrong. In your case this refers to the global context i.e) window.
you can simply use Object.create(A.prototype) to simply get all methods of A.
while executing this.methodsOfA[methodName]() - it calls the A's method with B's context. So, there is no property called name in your B context - it fail.
you have to call A's method with the context of A which is stored in B's context i.e) this.a
this.methodsOfA[methodName].call(this.a);
function A (name) {
this.name = name;
}
A.prototype.foo = function () {
this.name = this.name.toUpperCase();
};
A.prototype.bar = function () {
this.name = this.name.toLowerCase();
};
function B () {
this.a = new A('Hello, World!');
}
B.prototype.methodsOfA = Object.create(A.prototype);
B.prototype.executeMethodOfA = function (methodName) {
this.methodsOfA[methodName].call(this.a);
};
b = new B();
console.log(b.a.name);
b.executeMethodOfA('foo');
console.log(b.a.name);
b.executeMethodOfA('bar');
console.log(b.a.name);
I've an object looks like this:
var obj ={
property : '',
myfunction1 : function(parameter){
//do stuff here
}
}
I need to set some private properties and functions, which can not be accessed/seen from outside of the object. It is not working with
var property:, or var myFunction1
Next question is, if I call a function within or outside the object, I always have to do this with obj.myfunction(). I would like to asign "this" to a variable. Like self : this. and call inside the object my functions and variables with self.property and self.myfunction.
How? :)
There are many ways to do this. In short: If dou define a function inside another function, your inner function will be private, as long as you will not provide any reference to if.
(function obj(){
var privateMethod = function() {};
var publicMethod = function() {
privateMethod();
...
};
return {
pubMethod: publicMethod
}
}());
var obj = (function() {
var privateProperty;
var privateFunction = function(value) {
if (value === void 0) {
return privateProperty;
} else {
privateProperty = value;
}
};
var publicMethod = function(value) {
return privateFunction(value);
}
return {
getPrivateProperty: function() {
return privateFunction();
},
setPrivateProperty: function(value) {
privateFunction(value);
}
}
})();
obj.setPrivateProperty(3);
console.log(obj.getPrivateProperty());
// => 3
console.log(obj.privateProperty);
// => undefined
obj.privateFunction();
// => TypeError: undefined is not a function
Use closures. JavaScript has function scope, so you have to use a function.
var obj = function () {
var privateVariable = "test";
function privateFunction() {
return privateVariable;
}
return {
publicFunction: function() { return privateFunction(); }
};
}();
So I have this function called "createGameObjectConstructor" which takes a function and a prototype adds the prototype and a method to the function then returns the function.It can be used like this
Monster = createGameObjectConstructor(function () {
this.evilness = 9001;
}, {
eatHuman:function () {
console.log('human consumed');
}, type:'scary'
});
and "createGameObjectConstructor" looks like this
createGameObjectConstructor = (function () {
var recent = function () { //every actual object constructor will share this method
return (instance.length> 0) ? instance[instance.length - 1] :null;
};
return function (constructor, prototype) { //createGameObjectConstructor
var instanceArray = new Array();
constructor.prototype = prototype;
return function (){ //actual object's constructor
var instance = new constructor();
instance.constructor = constructor;
instanceArray.push();
return instance;
};
f.recent = recent;
return f;
}
}());
But when I call Monster().eatHuman(); in Chrome's console it returns the function undefined but with a weird arrow next to it, is this because my bizarre coding somehow led it too eval the code or something?
here's a fiddle http://jsfiddle.net/UZmL9/
This just means the return value of the function is undefined.
All JavaScript functions return undefined by default if no explicit return statement is found.
function foo(){
console.log("Hi");
}
foo(); // you will get the same 'undefined'
But
function foo(){
console.log("Hi");
return 5;
}
foo(); // you will get 5 with that arrow
I think I understand why variables exist outside of the function they were declared in, because you're returning another function:
myFunction = function() {
var closure = 'closure scope'
return function() {
return closure;
}
}
A = myFunction(); // myFunction returns a function, not a value
B = A(); // A is a function, which when run, returns:
console.log(B); // 'closure scope'
The way that it's written now, calling A() is like a getter.
Q: How can I write myFunction so that calling A(123) is a setter?
Try the following:
myFunction = function() {
var closure = 'closure scope'
// value is optional
return function(value) {
// if it will be omitted
if(arguments.length == 0) {
// the method is a getter
return closure;
} else {
// otherwise a setter
closure = value;
// with fluid interface ;)
return this;
}
}
}
A = myFunction(); // myFunction returns a function, not a value
A(123); // set value
B = A(); // A is a function, which when run, returns:
console.log(B); // '123'
You could do something like this if you want both getter and setter for example:
var func = function() {
var closure = 'foo';
return {
get: function() { return closure; },
set: function(value) { closure = value; }
}
};
var A = func();
A.set('foobar');
console.log(A.get()); //=> "foobar"
Should be as simple as:
myFunction = function() {
var closure = 'closure scope'
return function(setTo) {
if (typeof setTo !== "undefined") {
closure = setTo;
return this; //support call chaining, good idea hek2mgl
} else {
return closure;
}
}
}
Since the closure variable is within the closure of the function's scope, you should be able to assign to it the same way you can read from it.
See jsFiddle: http://jsfiddle.net/WF4VT/1/
Another alternative would be to use a class and define getters and setters:
function MyClass(p){
this._prop = p;
}
MyClass.prototype = {
constructor: MyClass,
get prop(){
return this._prop;
},
set prop(p){
this._prop = p;
}
}
var myObject = new MyClass("TEST");
console.log(myObject.prop);
myObject.prop = "test";
console.log(myObject.prop);
Demo: http://jsfiddle.net/louisbros/bMkbE/
jsFiddle Demo
Have your returned function accept an argument. Use it as a setter:
myFunction = function() {
var closure = 'closure scope';
return function(val) {
closure = val;
return closure;
}
}
A = myFunction(); // myFunction returns a function, not a value
B = A(123); // A is a function, which when run, returns:
console.log(B); // 'closure scope'
Revisiting this question, I see that I could do it this way:
function outside() {
var result = 'initialized'
return inside
function inside(argVariable) {
if(arguments.length) {
result = argVariable
return this
} else {
return result
}
}
}
myFunction = outside() // outside returns a function
X = myFunction() // returns: 'initialized'
$('body').append(X + '<br>')
myFunction(123) // setter
X = myFunction() // returns: 123
$('body').append(X)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
If I have a function like this:
function foo(_this) {
console.log(_this);
}
function bar() {}
bar.prototype.func = function() {
foo(this);
}
var test = new bar();
test.func();
then the test instance of bar gets logged.
However, for this to work I have to pass the this in the bar.prototype.func function. I was wondering whether it is possible to obtain the same this value without passing this.
I tried using arguments.callee.caller, but this returns the prototype function itself and not the this value inside the prototype function.
Is it possible to log the test instance of bar by only calling foo() in the prototype function?
If the question is 'without passing this (by any means)' then answer is no
value can be passed by alternative methods though. For example using global var (within Bar class) or session or cookies.
function bar() {
var myThis;
function foo() {
console.log(myThis);
}
bar.prototype.func = function() {
myThis = this;
foo();
}
}
var test = new bar();
test.func();
I think calling foo within the context of bar should work:
function foo() {
console.log(this.testVal);
}
function bar() { this.testVal = 'From bar with love'; }
bar.prototype.func = function() {
foo.call(this);
}
var test = new bar();
test.func(); //=> 'From bar with love'
You can do this without changing the external function, but you must change the way you call it.
You can't get the context of the caller, but you can set the this property on a function you call with the method apply or call. See this reference for an explanation on this.
function foo()
{
console.log( this );
}
function bar()
{
bar.prototype.func = function func()
{
foo.apply( this );
};
}
var test = new bar();
test.func();
Usually if this is used, it's in an object oriented context. Trying to call a method of an object with another this might indicate poor design. Explain a bit more what you are trying to achieve for more applicable design patterns.
For an example of a javascript OOP paradigm, check my answer here.
What about this?
"use strict";
var o = {
foo : function() {
console.log(this);
}
}
function bar() {}
bar.prototype = o;
bar.prototype.constructor = bar;
bar.prototype.func = function() {
this.foo();
}
var test = new bar();
test.func();
Or this:
"use strict";
Function.prototype.extender = function( o ){
if(typeof o == 'object'){
this.prototype = o;
}else if ( typeof o == 'function' ) {
this.prototype = Object.create(o.prototype);
}else{
throw Error('Error while extending '+this.name);
}
this.prototype.constructor = this;
}
var o = {
foo : function() {
console.log(this);
}
}
function bar() {}
bar.extender(o);
bar.prototype.func = function() {
this.foo();
}
var test = new bar();
test.func();