Javascript overwrite method and keep same this? - javascript

I want to overwrite a function, which is a method of a prototype of an Object. This method uses this internally. How can I overwrite that function but still keep this defined as the same object / value, as it has been in the original function?
The reasons I want to keep it are the following:
The original code supports extensions. I'd rather prefer writing an extension and add that to the code as intended by the authors of the original code, than changing the original code and having to build or install a modified version.
I need always perform some action before the original function is called. So I actually want to keep the original functionality, but want to add something before it. I think this would be "decorating" the function, like a decorator in Python.
The scope in code where I overwrite the function is not the same as where it is defined originally.
Here is some example code:
//original functions
var original_execute_cells = Jupyter.Notebook.prototype.execute_cells;
// decorating functions
function decorated_execute_cells(cell_indices) {
console.log('EXTENSION: running decorated execute_cells function');
return original_execute_cells(cell_indices);
}
// overwrite original functions
Jupyter.Notebook.prototype.execute_cells = decorated_execute_cells;
However, when I do that, I get a TypeError telling me that this is not defined, in the first line of the original function, which uses this.
The original source code of the function I am trying to overwrite can be found on github:
Notebook.prototype.execute_cells = function (indices) {
if (indices.length === 0) {
return;
}
var cell;
for (var i = 0; i < indices.length; i++) {
cell = this.get_cell(indices[i]);
cell.execute();
}
this.select(indices[indices.length - 1]);
this.command_mode();
this.set_dirty(true);
};

I now did it with bind. The return statement becomes:
return original_execute_cells.bind(Jupyter.notebook)(cell_indices);
Where Jupyter.notebook is in my specific case the object this related to, when the Notebook object was build.
However, what #siebetman mentioned in the comment could also work and might even be more flexible in some situations. Also the link siebetman provided seems very useful in order to understand Javascript's this better.

Why not just bind this?
var original_execute_cells = Jupyter.Notebook.prototype.execute_cells;
Jupyter.Notebook.prototype.execute_cells = function(cell_indices) {
console.log('EXTENSION: running decorated execute_cells function');
return original_execute_cells.bind(this)(cell_indices);
};

Related

running code in another function's scope (JavaScript)

So I'm working on a sort of JavaScript framework, just some utility things for myself to use in future projects, and I want to make a data binding system.
The first method I used was objects, and the code would just loop through the specified html element and look for occurences of {{key}} in the markup and then look for that key in the object and replace it that way in the HTML.
For example, if you had <div>{{name}} is a cool guy</div> in the HTML and had {name:"joseph"} in the JS then the final product would be displayed on screen as 'joseph is a cool guy'.
However, I decided later to change my method and instead the framework would except a function. So instead of {name:"joseph"} you would give it function(){ var name = "joseph" }.
This obviously looks better and gives a lot better functionality.
I changed the processing function so instead of looking for the key/value pair to replace the {{key}}, it just uses eval on the variable to gets its value.
My problem lies here: How do I run my search/replace code INSIDE the scope of the function the user passes.
If the user defines variables within that function, their values will not be available anywhere else due to scope issues.
I've tried using Function.toString() to actually modify the source code of the function, but nothing's working and it's all very complicated.
(The issues are not due to the actual solution, I think that Function.toString() might work, but due to my implementation. I keep getting errors)
So... What is the best way to run arbitrary code in the scope of another function?
Critera:
Obviously, I can't modify the function because the user is passing it in. (you can't just tell me to add the search/replace code to the bottom of the function)
The variables must stay in the local scope of the function. (no cheating by using window.name = "joseph" or anything)
I am also aware of how terrible eval is so any suggestions as to get it to work are greatly appreciated. Thanks!
Code:
function process(html) {
var vars = html.match( /({{)[^{}]*(}})/g )
// vars = ['{{variable}}', '{{anotherVariable}}']
var names = vars.map( function(x){ return x.replace("{{", "").replace("}}", "") } )
// names = ['variable', 'anotherVariable]
obj = {}
for (var i = 0; i < names.length; i++) {
obj[names[i]] = eval(names[i])
}
for (var p in obj) {
html = html.replace(new RegExp('{{'+p+'}}','g'), obj[p]);
}
return html
}
You should go back to your first method with the object, it's much better. You can still pass a function, but the function should return an object:
function () {
return { name: 'joseph' }
}

Only call constructor behaviour if particular function isn't called

Apologies - I have no idea to how to describe this. Example:
function OutputNumber(number) {
this.outputThisInstead = function (otherNumber) {
console.log(otherNumber);
}
console.log(number);
}
Desired usage:
new OutputNumber(1);
Console output: 1
new OutputNumber(1).outputThisInstead(2);
Console output: 2
Naturally, 1 will always be written to the console, irrespective of what else is called on the object.
I'm after this particular syntax, as well as the behaviour - attaching a function onto the initialisation. It feels impossible since the object must be constructed before any function is called on it, but is this achievable any other way?
It would be possible with a time delay (e.g., in a browser environment, setTimeout or similar) and a flag. Not desirable, but possible.
Without that, no, you can't base the action of the constructor on something that hasn't happened yet. You'd have to instead pass something into the constructor to let it know what was going on.
Browser example (again, I don't recommend this):
function OutputNumber(number) {
var handle = 0;
this.outputThisInstead = function (otherNumber) {
if (handle) {
clearTimeout(handle);
handle = 0;
}
console.log(otherNumber);
}
handle = setTimeout(function() {
console.log(number);
}, 0);
}
From your comment on the question:
This is the end of a sequence of chaining objects/functions, that I'm experimenting with. For example:
Assert.that(1).is.not(2).because('output this message if fails');
Here not(2) returns an object on which because can optionally be called. The behaviour of the object would depend on because being called.
Rather than have the behavior of an earlier function in the chain depend on a later function in the chain, I'd probably add an .end() at the end of something:
Assert.that(1).is.not(2).because('output this message if fails').end();
end would output whatever message/messages was/were stored by the previous functions. No need for black magic. Obviously this suffers from the fact that people could fail to put the .end() on, but you need some kind of trigger that it's okay to do the output, if you want the output to change based on an optional subsequent function call.
Not possible. By the time you do new OutputNumber(1) the function has already been called. A chained method will have no access to its preceding call.
It's possible to declare outputThisInstead as "static":
function OutputNumber(number) {
console.log(number);
}
OutputNumber.outputThisInstead = function (otherNumber) {
console.log(otherNumber);
}
new OutputNumber(1); //1
OutputNumber.outputThisInstead(2); //2
But if you want to create an object with the new operator the function will always log the number parameter.
You can also achieve similar behavior to the one you want with partial apply of the function (here). This is also called Currying or Schönfinkeling. The idea is that you can fill the function's parameters one after another and when the full set of parameters is available the function is being executed. You can see a currying example here.

How to serialize an object in JavaScript?

For example I have class:
function Test() {
}
Test.prototype = {
'setTest' : function(test) {
this.test = test;
}
}
var test = new Test();
Test.setTest('test');
I want to save object test in database.
How to serialize object test to string? (methods, variables, etc)
Simple with json
JSON.stringify( test );
In this case, for the question you're asking, there really isn't a way to do what you want. The problem with your request lies in "serializing everything attached to the object, including functions".
Serialization normally only occurs for data, because executables are usually machine bound, in that they are compiled for a given machine, based on certain characteristics. Now, it's reasonable to say that javascript functions just require a javascript interpreter, because javascript is write-once, run-everywhere. But when people write serializers, because all serializers tend to work the same, we write them for data only. In this case, the industry standard is JSON, which is an object-data only serializer.
There are three solutions that avail themselves to you at this point:
Write your own serialier/deserializer that encapsulates functions. This can be tricky, because not all javascript engines will give you access to the source.
Write your own re-loading mechanism that generates a specific new initialized type on each restore, and save the typename as one of the properties on serialization. That way the initialization of each variable gives you the methods, and then merging with the data gives you the complete object.
Store each function as a string and eval it on the fly as you need it. This is incredibly tricky, and is quite prone to errors. I can think of no case where this becomes helpful, because it's quite fragile. However, it is an option, and cannot be overlooked.
I know that 3 is a sub-answer for 1, so you can consider it that there are only two useful answers.
I know that superficially this works on Chrome and IE9, so it should work everywhere the majority of users are likely to use it:
var abc = function(thing) { return thing; }
abc.toString();
// gives "function(thing) { return thing; }" on the command line
So you can certainly serialize the methods as strings in place of the actual method, but you're going to need to create a duplicate object so you can capture every element on the source object (I think, rather than replacing them in place).
Hopefully this helps you think about the problem some more, and maybe to realize you don't need to serialize the methods (nobody ever does that I know of, not reasonably).
The best way to do this is to write your own serialize method which creates a JSON object with attributes, based on your getters. Normally you define a getter per attribute. So it should work for most cases (so you don't have to define a serialize method for each class).
function serialize(obj) {
var serialized = {};
for(var prop in obj) {
if (obj.hasOwnProperty(prop) && typeof obj[prop] == 'function') {
if (/^get.*/.test(prop)) {
var value = obj[prop]();
var name = prop.replace('get', '');
if (typeof value === 'object') {
serialized[name] = this.serialize(value);
continue;
}
serialized[name] = value;
}
}
}
return serialized;
};
To reset your attribute values back to the class you have two options:
Create a function in your class which creates a valid object instance based on the serialized JSON.
Create a unserialize method and map the JSON with your class using the setters.
Example:
function unserialize(obj, emptyClass) {
// Check emptyClass for setters and map the data from obj to it.
return 'class instance';
}
Typically, you'd do this with JSON, which is widely supported across browsers/languages/libraries/etc. The only hangup is that JSON does not support functions – but do you really need to serialize those?
I've had to support functionality similar to this before. I ended up saving the name of the function as a string and serializing it as JSON. Then when I come back to the client, I execute the function using a helper like the one posted in this question.
If anyone has a better way to solve this problem, I'd want to see it!
I recently had to find a solution for this problem. I'm sure it can be improved upon.
First I created a module for instantiating the "serialisable" object.
function MyObj(serialised){
this.val = "";
if(serialised){
var unserialised = JSON.parse(serialised);
for (var i in unserialised) {
this[i] = unserialised[i];
}
}
}
MyObj.prototype.myMethod = function () { return this.val;};
module.exports = MyObj;
you of course have to consider error handling and other validations.

Edit Javascript function

Is it possible to edit a JavaScript function after the page has loaded?
I want to edit a function dynamically after Loading.
You can't edit a function, but you can replace it, e.g.:
var myFunc = function() { return "Hello World"; };
myFunc = function() { return "Goodbye"; };
javascript functions are objects, so can be replaced by setting a new value. Is this what you mean?
Unless you are trying to hack some code that doesn't belong to you, the better solution is to write a more flexible initial javascript function who's behavior can be adapted based on conditions (parameters passed, environment, other state, data fetched from other sources, etc...). Then, the one function you have can be written once initially to handle all your different circumstances.
You can even use design patterns such as passing in callback functions that can be used to adapt the behavior at runtime. If you desire many callbacks, you can pass in an object that has a number of different optional methods and call those during your function. In this way you can significantly alter the behavior of the main function without ever changing it's code by passing in different callback functions.
For example, let's assume we have a parsing function that takes some tagged data structure as input and returns an array of results. We want to be able to modify the behavior of this parsing function by passing in callbacks. So, we write the parsing function to take a callback object. That callback object contains one or more methods (all of which are optional) and a state variable that is passed to each callback. Anyone who has worked with ajax or any asynchronous networking in Javascript will recognize the callback object concept. Here's some pseudo code for such a process that shows how the callback object can be used. A real function would obviously be a lot more involved than this one, but it hopefully illustrates the concept:
function parseMyData(data, callbacks) {
var output = []; // output we accumulate
var currentTag;
callbacks = callbacks || {}; // make the callbacks object optional
// do any preprocessing that the caller specified
if (callbacks.preProcessData) {
data = callbacks.preProcessData(data, callbacks.state);
}
[[code to parse to the first tag in the data (after doing so currentTag contains the tag we just parsed)]]
// give our callback object the opportunity to do something to this tag or return null to skip it
if (callbacks.preProcessTag {
currentTag = callbacks.preprocessTag(currentTag, callbacks.state);
}
if (currentTag) {
[[code here for the default processing of the tag that will push results into the output array]]
}
return(output);
}
If you want to add an action to the existing function you can "hijack" it by putting it in a temporary variable and calling it within your overwritten function. E.g.
// The original function.
function sayName(name) {
alert(name);
}
// Temporary variable for original function.
var __sayHello = sayName;
// Overwrite the original function, adding extra actions.
sayName = function(name) {
alert('Hello');
// Call the original function using its temporary variable.
__sayHello(name);
}
// Call the overwritten function.
sayName('Bob');
How to edit a function - 101.
If we reconsider that editing a function at runtime is not absolutely changing the guts of the function, but rather changing what the function guts are digesting, then I would say functions are already built to do just that.
example 1 - The guts cannot be changed.
function one(){
return true;
}
// one() => true;
// Note: We could still change the output without changing the guts.
// !one() => false;
example 2 = The guts can be created to digest a dynamic call.
function one(payload){
return payload;
}
// one(true) => true;
// one(false) => false;
// one('whatever I want to feed the guts to digest');
// => 'whatever I want to feed the guts to digest';
These are quite simple examples, but since you did not provide any real examples as to what you are trying to do, we have to assume you are attempting normal patterns of programming.
Considering NORMAL patterns of programming, it wouldn't be the function itself that needs to change, rather how you are calling it.
example 3 - Give the choice of which function to the caller.
function firstChoice(payload){
return http.post(payload);
}
function secondChoice(choice){
return `Do something else with ${choice}`;
}
// And where you make the choice, perhaps after a click event handler...
function onClick(choice, payload){
choice ? firstChoice(payload) : secondChoice(choice);
}
Functions are supposed to be small bricks with which you build logic. Give them something small to do, then select between them based on your logic.
To answer your question, in my opinion, assuming normal programming needs...
"Is it possible to edit a JavaScript function after the page has loaded?" YES.
Use arguments in your function definition to add the dynamic ability to suit your needs.

How to fix jslint error 'Don't make functions within a loop.'?

I am working on making all of our JS code pass through jslint, sometimes with a lot of tweaking with the options to get legacy code pass for now on with the intention to fix it properly later.
There is one thing that jslint complains about that I do not have a workround for. That is when using constructs like this, we get the error 'Don't make functions within a loop.'
for (prop in newObject) {
// Check if we're overwriting an existing function
if (typeof newObject[prop] === "function" && typeof _super[prop] === "function" &&
fnTest.test(newObject[prop])) {
prototype[prop] = (function(name, func) {
return function() {
var result, old_super;
old_super = this._super;
this._super = _super[name];
result = func.apply(this, arguments);
this._super = old_super;
return result;
};
})(prop, newObject[prop]);
}
}
This loop is part of a JS implementation of classical inheritance where classes that extend existing classes retain the super property of the extended class when invoking a member of the extended class.
Just to clarify, the implementation above is inspired by this blog post by John Resig.
But we also have other instances of functions created within a loop.
The only workaround so far is to exclude these JS files from jslint, but we would like to use jslint for code validation and syntax checking as part of our continuous integration and build workflow.
Is there a better way to implement functionality like this or is there a way to tweak code like this through jslint?
Douglas Crockford has a new idiomatic way of achieving the above - his old technique was to use an inner function to bind the variables, but the new technique uses a function maker. See slide 74 in the slides to his "Function the Ultimate" talk. [This slideshare no longer exists]
For the lazy, here is the code:
function make_handler(div_id) {
return function () {
alert(div_id);
};
}
for (i ...) {
div_id = divs[i].id;
divs[i].onclick = make_handler(div_id);
}
(I just stumbled on this questions many months after it was posted...)
If you make a function in a loop, an instance of a function is created for each iteration of the loop. Unless the function that is being made is in fact different for each iteration, then use the method of putting the function generator outside the loop -- doing so isn't just Crockery, it lets others who read your code know that this was your intent.
If the function is actually the same function being assigned to different values in an iteration (or objects produced in an iteration), then instead you need to assign the function to a named variable, and use that singular instance of the function in assignment within the loop:
handler = function (div_id) {
return function() { alert(div_id); }
}
for (i ...) {
div_id = divs[i].id;
divs[i].onclick = handler(div_id);
}
Greater commentary/discussion about this was made by others smarter than me when I posed a similar question here on Stack Overflow:
JSlint error 'Don't make functions within a loop.' leads to question about Javascript itself
As for JSLint:
Yes, it is dogmatic and idiomatic. That said, it is usually "right" -- I discover that many many people who vocalize negatively about JSLint actually don't understand (the subtleties of) Javascript, which are many and obtuse.
Literally, get around the problem by doing the following:
Create a .jshintrc file
Add the following line to your .jshintrc file
{"loopfunc" : true, // tolerate functions being defined in loops }
JSLint is only a guide, you don't always have to adhere to the rules. The thing is, you're not creating functions in a loop in the sense that it's referring to. You only create your classes once in your application, not over and over again.
If you are using JQuery, you might want to do something like this in a loop:
for (var i = 0; i < 100; i++) {
$("#button").click(function() {
alert(i);
});
}
To satisfy JSLint, one way to work around this is (in JQuery 1.4.3+) to use the additional handler data argument to .click():
function new_function(e) {
var data = e.data; // from handler
alert(data); // do whatever
}
for (var i = 0; i < 100; i++) {
$("#button").click(i, new_function);
}
Just move your:
(function (name, func) {...})()
block out of the loop and assign it to a variable, like:
var makeFn = function(name, func){...};
Then in the loop have:
prototype[prop] = makeFn(...)

Categories