Change function in function - javascript

I have ready code something like this and
I can't change function Foo() because it's alias framework.
function Foo(){
this.prop = {
width: 200
}
this.do = function(s1,s2){
alert(s1+s2);
}
}
I need change do function.
After function Foo() and before var foo1 = new Foo(); foo1.do(1,0); I try write
Foo.do = function(){
alert('changed');
}
I can't change do function. I used defineProperty and even constructor) I haven't prototype.
Full uncorrect demo code
function Foo(){
this.prop = {
width: 200
}
this.do = function(s1,s2){
alert(s1+s2);
}
}
Foo.do = function(){
alert('changed');
}
var foo1 = new Foo();
foo1.do(1,0);
var foo2 = new Foo();
foo2.do(1,1);
var foo3 = new Foo();
foo3.do(1,2);
I can change it for foo1, foo2 and etc. I need cange it ine time.

I'd suggest creating your own constructor that implements Foo.
function Foo() {
this.prop = {
width: 200
}
this.do = function (s1, s2) {
console.log(s1 + s2);
}
}
Foo.prototype.someMethod = function () {};
// can't change any of the above..
function MyFoo() {
Foo.call(this);
this.oldDo = this.do;
this.do = function (s1, s2, s3) {
// do something else!
console.log(s1 + s2 + s3);
}
}
MyFoo.prototype = Object.create(Foo.prototype);
// tests...
var foo = new Foo();
foo.do(2, 2, 2); // 4
console.log(foo.prop.width); // 200
var myFoo = new MyFoo();
myFoo.do(2, 2, 2); //6
console.log(myFoo.prop.width); // 200
Your new constructor only has to override the methods you want to change, the rest will stay the same and the original isn't changed. Notice how instances of MyFoo also have a .prop property even though that was done in Foo's constructor, not MyFoo.

newDo = function(){}; // your new do function
var foo1 = new Foo()'
foo1.do = newDo;
foo1.do(1,0)
and so on. If you can't change the Foo function, and you can't restrict yourself to ES6 or Firefox (they have ways to modify the prototype), then the best option is to overwrite do after creating a new Foo.
This is also a good point to plug learning the module pattern so that you can create your own nested versions of things:
function Foo() {}; //your original foo
(function() {
function Foo() {}; //your new foo with a new do method
// do stuff with the modified do here
})()

Related

Can I save object prototype in local storage?

I have JS object with custom methods as prototype (e. g. Foo.prototype.myAwesomeMethod). If I load my object in a localStorage and get it later I'll loose these methods.
var foo = new Foo()
console.log(foo.myAwesomeMethod()) // WIN
localStorage.setItem('foo', foo)
foo = localStorage.getItem('foo')
console.log(foo.myAwesomeMethod()) // FAIL...
Is it possible to save the prototype of the object in the localStorage ? If not, how to properly re-instantiate the class?
you can try this
function Foo() {
this.bar = 1;
}
Foo.prototype.myAwesomeMethod = function () {
return "And the winner is " + this.bar;
}
var foo;
window.onload = function () {
foo = new Foo();
foo.bar = 3;
console.log(foo.myAwesomeMethod()); // "And the winner is 3"
var test = JSON.stringify(foo); //localStorage.setItem('foo', foo);
foo = JSON.parse(test); // = localStorage.getItem('foo');
foo.__proto__ = new Foo(); // <--------------
console.log(foo.myAwesomeMethod()); // "And the winner is 3"
});
EDIT:
my previous code was untested and didn't work, this is the working code

How to create a new object from an existing one?

This doesn't work, and I have no idea how to fix it
function bar() {...}
function foo() {
this = new bar();
this.newfunction = function() {...};
this.newvalue = "foobar";
}
var foobar = new foo();
Thanks in advance,
Do not use this to represent another object.
function bar() {...}
function foo() {
var bar = new bar();
bar.newfunction = function() {...};
bar.newvalue = "foobar";
}
var foobar = new foo();
Are you trying to inherit from bar? Then you can borrow its constructor and all its own properties using call (or apply):
function bar() {...}
function foo() {
bar.call(this);
this.newfunction = function() {...};
this.newvalue = "foobar";
}
var foobar = new foo();

How to get 'this' value of caller function?

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();

Getting a 'this' reference to a 2nd level prototype function

I'm fairly certain this isn't possible, but wanted to see if anyone had some ingenious ideas as to how to make it possible.
I want the following code to work:
var x = new foo();
x.a.getThis() === x; // true
In other words, I want x.a.getThis to have a reference to this being x in this case. Make sense?
In order to get this to work one level deep is simple:
function foo(){}
foo.prototype.getThis = function(){ return this; }
var x = new foo();
x.getThis() === x; // true
One thing, I want this to work as a prototype, no "cheating" by manually binding to this:
function foo(){
this.a = {
getThis : (function(){ return this; }).bind(this)
};
}
Although the above is a perfect functional example of what I'm trying to achieve, I just don't want all the extra functions for each instance :)
FYI, the actual use case here is that I'm creating classes to represent Cassandra objects in node and I want to be able to reference a super-column --> column-family --> column via foo.a.b and keep a reference to foo in the deep function.
You can't do this without a forced bind of some kind. You say you don't want to "cheat" but this breaks the standard rules about what this is, so you have to cheat. But JS lets you cheat, so it's all good.
BTW, for what it's worth coffee script makes this so trivial.
foo = ->
#a = getThis: => this
The fat arrow => preserves the context of this for from the scope it was called in. This allows you to easily forward the context to another level.
That code gets compiled to this JS:
var foo;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
foo = function() {
return this.a = {
getThis: __bind(function() {
return this;
}, this)
};
};
Which basically just does what you say you do not want to do.
Or if the value doesn't have to this specifically, you can set the "owner" in the child object.
var A = function(owner) {
this.owner = owner;
};
A.prototype.getThis = function() {
return this.owner;
};
var Foo = function() {
this.a = new A(this);
};
var foo = new Foo();
if (foo.a.getThis() === foo) {
alert('Happy dance');
} else {
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png';
}
http://jsfiddle.net/4GQPa/
And the coffee script version of that because I am a passionate and unreasonable zealot for it:
class A
constructor: (#owner) ->
getThis: -> #owner
class Foo
constructor: -> #a = new A(this)
foo = new Foo()
if foo.a.getThis() is foo
alert 'Happy Dance'
else
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png'
Impossible to do reliably without binding the value at the start since the value of a function's this is set by the call. You can't know beforehand how it will be called, or which functions need a special or restricted call to "preserve" the this -> this relationship.
The function or caller's this may be any object, there may not be a this -> this at all. Consider:
var x = {
a : {
b: function() {return this;}
}
}
When you call x.a.b(), then b's this is a. But if you do:
var c = x.a.b;
c(); // *this* is the global object
or
x.a.b.call(someOtherObject);
What is the value of this -> this in these cases?
Answering my own question because someone else may find it useful. Not sure if I'll end up going with this or Squeegy's solution. The functions are only ever defined once and then the containing object is cloned and has parent = this injected into it:
function foo(){
var self = this, nest = this.__nestedObjects__ || [];
nest.forEach(function(prop){
self[prop] = extend({ parent : self }, self[prop]);
});
}
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
bar : {
enumerable : true,
value : {
foobar : function(){
return this.parent;
},
foo : function(){},
bar : function(){}
}
},
__nestedObjects__ : { value : ['bar'] }
});
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);
or based on Squeegy's solution:
function foo(){
for(var cls in this.__inherit__){
if(!this.__inherit__.hasOwnProperty(cls)){ continue; }
this[cls] = new (this.__inherit__[cls])(this);
}
}
var clsA;
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
__inherit__ : { value : {
bar : clsA = function(parent){
Object.defineProperty(this, '__parent__', { value : parent });
}
}
}
});
clsA.prototype = {
foobar : function(){
return this.__parent__;
}
};
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);

function caller name in an anonymous function

Im guessing there is no way to get the function caller name in an anonymous function, is there ?
(function()
{
var cls = function()
{
this.foo = function()
{
console.log(arguments.callee.caller); // null
foo1();
}
var foo1 = function()
{
console.log(arguments.callee.caller); // foo
foo2();
}
var foo2 = function()
{
console.log(arguments.callee.caller); // foo1
cls.foo(); // local
}
var cls =
{
foo : function()
{
console.log(arguments.callee.caller); // cls.foo2
}
}
}
return (window.cls = cls);
})();
var c1 = new cls();
c1.foo();
Correct - they're anonymous. If you need to know their names by callee, you'll need to give them a name. Will something like this.foo = function foo() rather than this.foo = function() work for you?
It is possible in recent versions of Chrome and Firefox as follows. I only recommend this for debugging purposes (e.g. javascript tracing in non-production)
var mystery = function() {
var myNameInChrome = /.*Object\.(.*)\s\(/.exec(new Error().stack)[1];
var myNameInFF = new Error().stack.split("#")[0];
}

Categories