I'm trying to clone the function indexedDB.cmp in Chrome, then replace indexedDB.cmp with a new function. The new function logs the passed arguments using console.log, then calls the cloned function using apply. However, I keep getting the error "Illegal Invocation" when I use apply. I only need this to work on Google Chrome. Any help would be appreciated!
function init() {
var i = indexedDB;
i.cmp2 = i.cmp.bind({});
i.cmp = function(...a) {
console.log("CMP call!",a);
return i.cmp2.apply(null,a);
};
}
init();
indexedDB.cmp("/testFolder",3);
"Since you're already using spread syntax, why not invoke the function with spread instead of apply? – Mikael Lennholm"
I also changed i.cmp.bind({}) to i.cmp.bind(i).
Related
I am trying to detect when a function is created, preferable through a constructor. Functions are a type of object, right? So it makes sense that when you create a new one, it calls a constructor. Is there a way to override this, for example, something like this
var old = Function.constructor;
Function.constructor = () => {
alert('new function created!');
old();
};
function asdf() {}
var k = new Function();
If this is not possible, is there a way to get all currently defined functions? I am trying to trigger a piece of code on each function run.
You can't detect function creation.
Functions are a type of object, right?
Yes.
So it makes sense that when you create a new one, it calls a constructor.
No. Or - maybe, but that constructor is internal. Just like the construction of objects from array literals, object literals, regex literals, definition of a function directly creates a native object.
Is there a way to override this?
No. You'd need to hook into the JS engine itself for that.
If this is not possible, is there a way to get all currently defined functions?
No. At best, you could try the debugging API of the JS engine and get a heap snapshot, that should contain all function objects.
I am trying to trigger a piece of code on each function run.
Let me guess, that piece of code is a function itself?
Was able to get a semi-working attempt at this. It reads only global functions but it can add code to both the front and beginning of the function. Any tips on how to improve this, as I use classes a lot when I code?
Thanks to Barmar for the idea of looping through window properties, but since you can't access local functions and class functions, this may be the closest way to do this
<script>
function prepend(name) {
console.time(name);
}
function postpend(name) {
console.timeEnd(name);
}
var filter = ['prepend', 'postpend', 'caches'];
function laggyFunction() {
var l = 0;
while (l<1000) {l++}
}
var functions = [];
for (var property in window) {
try {
if (!filter.includes(property)) { // security error on accessing cache in stackoverflow editor along with maximum call stack size exceeded if prepend and postpend are included
if (typeof window[property] === 'function') {
window[property].original = window[property];
window[property].name = property;
window[property] = function() {
prepend(this.name);
console.log(this.original);
this.original.apply(null, arguments);
postpend(this.name);
}.bind(window[property]);
functions.push(property);
}
}
} catch(e) {
console.warn(`Couldn't access property: `+property+' | '+e);
}
}
document.write(functions); // functions the prepend and postpend are applied to
laggyFunction(); // test performance of the function
</script>
I am very new to Javascript and I just stuck with something that works in python.
The problem is that I have class where I initiate some empty lists as this.data_y_json and etc. If I make normal function inside class like normal_function(){this.data_y_json = 5} it works and the variable is changed.
However, i work with d3, and there is some trick which I cant get through:
// inside class
// in constructor all this.xxx defined
// after object initiation I call set_data()
set_data(){
d3.json("link2.json",function(data) {
for (var i=0;i<data.d.results.length;i++){
this.data_y_json.push(parseFloat(data.d.results[i].PE))
...
//end of function
// end of class
After calling function set_data() an error is raised: SCRIPT5007: Unable to get property 'data_y_json' of undefined or null reference
I am rewriting my visualization into OOP, before this, I had it solved with global variables and it worked fined. In python I would just passed 'self' as an argument to function, but here in javascript, passing THIS doesnt work and raises another error.
Simply said, I know the problem -> this.data_y_json is not recognized propably because of function(data) doesnt pass self of the object, but I dont know how to do it.
Thank in advance for advice
Are you in an ES2015 environment? Changing your callback to be an arrow function should scope this to be what you want
d3.json("link2.json", (data) => {
for (var i=0;i<data.d.results.length;i++){
this.data_y_json.push(parseFloat(data.d.results[i].PE))
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
For reading up on the arrow function and the scoping of this
I'm trying to clean my code a bit, so I create some small objects or libraries (call it how you want) like:
function myLib() {
this.get = function() { ... };
...
};
Problem is when I try to call it like myLib.get(). It throws the following error:
Uncaught TypeError: myLib.get is not a function
I've tried to encapsulate the call into $(document).ready(), but it did not help.
Can you help me, please?
Thanks!
myLib is used for "libary", and you want to call this "get" method of libary.
Static instance is better in your case.
const myLib = {
get:function(){},
get2:function(){}
...
};
myLib.get();
myLib.get2();
so I create some small objects or libraries (call it how you want)
In your case you are creating a constructor, myLib is a constructor and not just a function, and you can't access a function's properties and methods directly that's why you got the Exception.
So you need to get an instance of myLib in order to call the get method or to access any of its members(methods).
function myLib() {
this.get = function() { console.log("get called!!"); };
};
let lib = new myLib();
lib.get();
Note:
And from the MDN Reference for Functions you can see that:
The this keyword does not refer to the currently executing function, so you must refer to Function objects by name, even within the function body.
You should use myLib as a constructor ie:
var lib = new myLib();
lib.get();
I'm no doubt doing something dumb here, but the following code results in an
error "this.getString is not a function."
This occurs because when unrelatedInstance calls stringGetter, "this" in showCombinedStrings() has the value of Unrelated....which actually seems fair enough, but how could this be set up so that it would work?
function BaseStringGetter() {
this.getString = function () {
return 'this is from BaseStringGetter';
}
}
function DerivedStringGetter() {
this.showCombinedStrings = function () {
console.log( 'this is from DerivedStringGetter and... ' + this.getString() );
}
}
DerivedStringGetter.prototype = new BaseStringGetter();
var stringGetterInstance = new DerivedStringGetter();
function Unrelated() {};
var unrelatedInstance = new Unrelated();
unrelatedInstance.stringGetter = stringGetterInstance.showCombinedStrings;
unrelatedInstance.stringGetter();
One option is this:
unrelatedInstance.stringGetter =
stringGetterInstance.showCombinedStrings.bind(stringGetterInstance);
unrelatedInstance.stringGetter();
Here, you're using Function.prototype.bind() to make this inside of unrelatedInstance.stringGetter() always refer back to stringGetterInstance.
The problem is how you are calling unrelatedInstance.stringGetter();
Even though stringGetter refers to the showCombinedStrings function, this inside showCombinedStrings now refers to the unrelatedInstance instance which does not have the toString() property that is why the error.
Demo: Fiddle
Here the value of this is printed as Unrelated {stringGetter: function} which is not an DerivedStringGetter instance
One easy solution is to use .bind() to give a custom execution context to unrelatedInstance.stringGetter like
unrelatedInstance.stringGetter = stringGetterInstance.showCombinedStrings.bind(stringGetterInstance);
Demo: Fiddle
Now even if you call unrelatedInstance.stringGetter(), this inside showCombinedStrings will refer to the stringGetterInstance instance.
When you call a function on an object, this will refer to the object the function is invoked on even if the function was originally defined elsewhere.
When you call unrelatedInstance.stringGetter();, this inside the function will now refer to unrelatedInstance which doesn't have getString(). The MDN this reference page has more info.
You could do something like this to preserve the original context:
unrelatedInstance.stringGetter = function() {
return stringGetterInstance.showCombinedStrings();
}
Edit: I left out bind that the other answers have now mentioned since it doesn't exist in IE8 but you'd be fine using that if you have a shim or don't care about old browsers.
I have a problem when calling a function from a button in HTML that gives me the: "Uncaught TypeError: undefined is not a function" error. I don't think there's anything wrong here.. Or there is something that I haven't taken into account. Thanks in advance for answering!
I have a lot of JS files, this is because this is a school assignment and we're now learning the Model, View, Controller (MVC) method.
I have this button:
<button onClick="ControllerBKE.reageerOpKlik()">Ok!</button>
I then have this Javascript code that creates an object of ^ "ControllerBKE":
"use strict"
window.onload = reageerOpStart();
function reageerOpStart()
{
var controllerBKE = new ControllerBKE();
}
Here is the line of code that is in the "ControllerBKE" that should, but is not reacting to the button:
function ControllerBKE(){
this.reageerOpKlik = reageerOpKlik;
function reageerOpKlik(){
alert('hoi');
}
}
This is just a small portion of a big code. But I get the error message when I click on the button instead of getting an alert with 'hoi'.
reageerOpKlik is an instance method. You have to use it from an instance. The simplest solution (not the best) is to create a global controller instance. There are many ways you could get rid of that global variable, but it's beyond the scope of the question.
function reageerOpStart()
{
window.controllerBKE = new ControllerBKE();
}
<button onClick="window.controllerBKE.reageerOpKlik()">Ok!</button>
The problem is that your code
<button onClick="ControllerBKE.reageerOpKlik()">Ok!</button>
is trying to call reageerOpKlik on your prototype object ControllerBKE.
What you probably mean is
<button onClick="controllerBKE.reageerOpKlik()">Ok!</button>
where controllerBKE is an instance of your prototype.
However, you have another problem. The function:
function reageerOpStart()
{
var controllerBKE = new ControllerBKE();
}
Creates controllerBKE in the scope of the reageerOpStart function, meaning that it's not avaiable in the global scope, which is where your button click handler would expect it.
You might want to consider:
<button onClick="APP.controllerBKE.reageerOpKlik()">Ok!</button>
APP = {}
function reageerOpStart()
{
APP.controllerBKE = new ControllerBKE();
}
Or, better still:
<button id="myButton">Ok!</button>
function reageerOpStart()
{
var controllerBKE = new ControllerBKE();
document.getElementById("myButton").addEventListener("click", function() {
controllerBKE.reageerOpKlik();
});
}
What you have is referred to as a closure. Your function has a limited scope. That is, it can only be called inside of ControllerBKE() where it is defined, not from outside the function.
What you have effectively done though is expose that closure via a property on your instance of ControllerBKE. While this works, it would fit more with the prototypal structure of JavaScript to add it to ControllerBKE.prototype.
It's important to remember that JavaScript is Prototypal not Object Oriented. While this may act similar to object oriented encapsulation, the two have different concepts and uses.
Look at the following example:
HTML:
<button onclick="controllerBKE.reageerOpKlik()">Ok!</button>
JavaScript:
"use strict";
window.controllerBKE = new ControllerBKE();
function ControllerBKE () { }
ControllerBKE.prototype.reageerOpKlik = function () {
alert('hoi');
}
I've simplified some of your code and refactored it to support the prototype object that JavaScript provides us with.
The first line is adding the controllerBKE variable to the window object. This gives it a global scope across the page, allowing your onclick function to have access to it.
The next line is a simple function wrapper. This will create an instance of ControllerBKE of type object.
The function you're trying to call is now attached to the prototype of ControllerBKE. This means that any instances of ControllerBKE created with the new keyword will have access to this function.
Check out the full functionality in the fiddle below:
FIDDLE
References:
Object.prototype
Object Oriented JavaScript