I am trying to port some javascript to actionscript 3. I am new to javascript, and whereas much of js is familiar, I am having a devil of a time deciphering some js code. A global variable, "action", seems to be defined in a function prototype call, which is then apparently referenced later as a function parameter in the body of the script:
Variable "action" Definition:
function SteppedAction(proUpdater, unbrInterval, slInterval) {
}
SteppedAction.prototype.getResult = function
SteppedAction_getResult(recipient)
{
this.subactions.push({
action: function(action)
{
// function body
},
prop: 0
});
return this;
};
In the body of the script, this same "action" seems to be referenced again in other functions, even though it appears to be defined as a function parameter itself in other anonymous functions and as an argument in the generatePl() function:
function generate () {
activeAction = new SteppedAction(updateProgressUI)
.executeSubaction(function(action) { ui.progressPanel.show(); }, 0)
.executeSubaction(function(action) { generatePl(subdivs,
dist, count, rate, level, action); });
}
I am using Sublime Text to help decipher the javascript, and when I hover over any of the "action" named variables anywhere in the script, whether as function parameters or function call arguments, it references the original "action" in the definition given above. I simply do not understand this. How does a function parameter "know" it is referring to the original variable definition, unless function parameters in anonymous functions can somehow obtain global scope? I do not use anonymous functions normally.
The code for the SteppedAction.executeSubaction() is:
SteppedAction.prototype.executeSubaction = function
SteppedAction_executeSubaction(subaction, proportion, name) {
proportion = (typeof(proportion) === "number" && proportion >= 0) ?
proportion : 1;
this.subactions.push({ action: subaction, proportion: proportion,
name: name });
return this;
};
Any help would be greatly appreciated.
The short answer to your question is that the variable name of a function declaration is independent of its surrounding body. The variable name will "shadow" any previously declared variable. For example:
const action = "local variable";
const myFn = (action) => console.log("inside fn, action is", action);
myFn("other variable")
You'll notice that in this case, even though the myFn has a function argument of action it is completely independent of the action in the outer scope.
Similarly, it's important to note that this.subactions is storing a function as action, and not executing the action. Here's an example:
const subactions = [];
const myFn = (action) => console.log("calling myFn with", action);
console.log("about to push subactions");
subactions.push({action: myFn});
console.log("action pushed");
console.log("calling myFn");
subactions[0].action("other variable");
Notice that, very similarly to the above, the action parameter of myFn isn't set until it's called, and it has nothing to do with the outer scope. I hope this clears up your questions.
Addendum
I was putting together your code snippets and here's the ES2015 version of your code, if it helps. Hopefully the syntax is a bit more understandable.
class SteppedAction {
constructor(proUpdater, unbrInterval, slInterval) {
this.subactions = []; // missing but presumably exists
}
getResult(recipient) {
this.subactions.push({
action: (a) => {},
prop: 0, // should this be proportion to match executeSubaction?
});
return this;
}
executeSubaction(subaction, proportion, name) {
proportion = (typeof(proportion) === "number" && proportion >= 0) ?
proportion : 1;
this.subactions.push({
action: subaction,
proportion: proportion,
name: name
});
return this;
}
}
const generate = () => {
const activeAction = new SteppedAction();
// ui is not defined here.
activeAction.executeSubaction(() => ui.progressPanel.show(), 0);
// several of these variables are not defined in the code snippet
activeAction.executeSubaction((action) => generatePl(subdivs, dist, count, rate, level, action));
}
So, here's what I found out (at least how the Sublime Text text editor seems to work) through fiddling with the text editor: when one defines a function at the global level, (named or assigned to a variable or object), that function is evidently assigned a namespace that is referenced within the rest of the program, including function parameter definitions and arguments.
Thus,
myArray.push(action: function(x){});
var action = function(x){};
function action(x){}
will all create a reference to themselves for future calls using the "action" identifier (including within function parameter signatures), so that the parameter, "action," in
var myFunction(action) {}
will reference all three of the function declarations above when the cursor is hovered over it, giving line numbers where each are defined/declared. This only seems to happen with global function declarations. Regular global variables with a single value ARE NOT referenced within function parameter signatures like function declarations are.
As long as this is a quirk in Sublime Text itself and not some strange convention in javascript, where global function declarations create a namespace issue within subsequent function parameter signatures, I can understand it, and ignore it in the future. Thanks for the help!
Related
Here is a simplified snippet from some code I wrote for managing tablet gestures on canvas elements
first a function that accepts an element and a dictionary of callbacks and register the events plus adding other features like 'hold' gestures:
function registerStageGestures(stage, callbacks, recieverArg) {
stage.inhold = false;
stage.timer = null;
var touchduration = 1000;
var reciever = recieverArg || window;
stage.onLongTouch = function(e) {
if (stage.timer) clearTimeout(stage.timer);
stage.inhold = true;
if (callbacks.touchholdstart) callbacks.touchholdstart.call(reciever, e);
};
stage.getContent().addEventListener('touchstart', function(e) {
e.preventDefault();
calcTouchEventData(e);
stage.timer = setTimeout(function() {
stage.onLongTouch(e);
}, touchduration);
if (callbacks.touchstart) callbacks.touchholdstart.call(reciever, e);
});
stage.getContent().addEventListener('touchmove', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdmove) callbacks.touchholdmove.call(reciever, e);
} else {
if (callbacks.touchmove) callbacks.touchmove.call(reciever, e);
}
});
stage.getContent().addEventListener('touchend', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdend) callbacks.touchholdend.call(reciever, e);
} else {
if (callbacks.touchend) callbacks.touchend.call(reciever, e);
}
stage.inhold = false;
});
}
later I call registerStageGestures on a few elements (represented by 'View' objects) in the same page. Something like:
function View() {
var self=this;
..
function InitView() {
...
registerStageGestures(kineticStage, {
touchstart: function(e) {
// do something
},
touchmove: function(e) {
// do something
},
touchendunction(e) {
// do something
},
touchholdstart: function(e) {
// do something
},
touchholdmove: function(e) {
// do something
},
touchholdend: function(e) {
// do something
},
}, self);
Everything works fine, however I'm left wondering about two things in the implementation of registerStageGestures:
First, is it necessary to make inhold, timer and onLongTouch members of the stage ? or will closures make everything works well if they are local vars in registerStageGestures ?
Second, is it necessary to call the callbacks with '.call(receiver,' syntax ? I'm doing this to make sure the callback code will run in the context of the View but I'm not sure if it's needed ?
any input is much appreciated
Thanks!
First, is it necessary to make inhold, timer and onLongTouch members
of the stage ? or will closures make everything works well if they are
local vars in registerStageGestures ?
As far as registerStageGestures() is concerned, var inhold, var timer and function onLongTouch(e) {...}. would suffice. The mechanism by which an inner function has automatic access to its outer function's members is known as "closure". You would only need to set stage.inhold, stage.timer and stage.onLongTouch if some other piece of code needs access to these settings as properties of stage.
Second, is it necessary to call the callbacks with '.call(receiver,'
syntax ? I'm doing this to make sure the callback code will run in the
context of the View but I'm not sure if it's needed ?
Possibly, depending on how those callbacks are written. .call() and .apply() are sometimes used when calling functions that use this internally. In both cases, the first parameter passed defines the object to be interpreted as this. Thus, javascript gives you the means of defining general purpose methods with no a priori assumption about the object to which those methods will apply when called. Similarly, you can call a method of an object in such a way that it acts on another object.
EDIT:
For completeness, please note that even in the absence of this in a function, .apply() can be very useful as it allows multiple parameters to be specified as elements of a single array, eg the ubiquitous jQuery.when.apply(null, arrayOfPromises)...
There are some simple answers, here.
First, closure:
Closure basically says that whatever is defined inside of a function, has access to the rest of that function's contents.
And all of those contents are guaranteed to stay alive (out of the trash), until there are no more objects left, which ere created inside.
A simple test:
var testClosure = function () {
var name = "Bob",
recallName = function () { return name; };
return { getName : recallName };
};
var test = testClosure();
console.log(test.getName()); // Bob
So anything that was created inside can be accessed by any function which was also created inside (or created inside of a function created in a function[, ...], inside).
var closure_2x = function () {
var name = "Bob",
innerScope = function () {
console.log(name);
return function () {
console.log("Still " + name);
}
};
return innerScope;
};
var inner_func = closure_2x();
var even_deeper = inner_func(); // "Bob"
even_deeper(); // "Still Bob"
This applies not only to variables/objects/functions created inside, but also to function arguments passed inside.
The arguments have no access to the inner-workings(unless passed to methods/callbacks), but the inner-workings will remember the arguments.
So as long as your functions are being created in the same scope as your values (or a child-scope), there's access.
.call is trickier.
You know what it does (replaces this inside of the function with the object you pass it)...
...but why and when, in this case are harder.
var Person = function (name, age) {
this.age = age;
this.getAge = function () {
return this.age;
};
};
var bob = new Person("Bob", 32);
This looks pretty normal.
Honestly, this could look a lot like Java or C# with a couple of tweaks.
bob.getAge(); // 32
Works like Java or C#, too.
doSomething.then(bob.getAge);
? Buh ?
We've now passed Bob's method into a function, as a function, all by itself.
var doug = { age : 28 };
doug.getAge = bob.getAge;
Now we've given doug a reference to directly use bobs methid -- not a copy, but a pointer to the actual method.
doug.getAge(); // 28
Well, that's odd.
What about what came out of passing it in as a callback?
var test = bob.getAge;
test(); // undefined
The reason for this, is, as you said, about context...
But the specific reason is because this inside of a function in JS isn't pre-compiled, or stored...
this is worked out on the fly, every time the function is called.
If you call
obj.method();
this === obj;
If you call
a.b.c.d();
this === a.b.c;
If you call
var test = bob.getAge;
test();
...?
this is equal to window.
In "strict mode" this doesn't happen (you get errors really quickly).
test.call(bob); //32
Balance restored!
Mostly...
There are still a few catches.
var outerScope = function () {
console.log(this.age);
var inner = function () {
console.log("Still " + this.age);
};
inner();
};
outerScope.call(bob);
// "32"
// "Still undefined"
This makes sense, when you think about it...
We know that if a function figures out this at the moment it's called -- scope has nothing to do with it...
...and we didn't add inner to an object...
this.inner = inner;
this.inner();
would have worked just fine (but now you just messed with an external object)...
So inner saw this as window.
The solution would either be to use .call, or .apply, or to use function-scoping and/or closure
var person = this,
inner = function () { console.log(person.age); };
The rabbit hole goes deeper, but my phone is dying...
I have this function:
function db_borrarServer(idABorrar){
serversDB.servidores
.filter(function(elementoEncontrado) {
return elementoEncontrado.id_local == this.idABorrar;
})
.forEach(function(elementoEncontrado){
console.log('Starting to remove ' + elementoEncontrado.nombre);
serversDB.servidores.remove(elementoEncontrado);
serversDB.saveChanges();
});
}
does not work, but it does if I replace the variable "this.idABorrar" with a number, it does
return elementoEncontrado.id_local == 3;
or if I declare idABorrar as a global, works to.
I need to pass idABorrar as variable. How can I do this?
The EntitySet filter() function (as any other predicate functions) are not real closure blocks, rather an expression tree written as a function. To resolve variables in this scope you can only rely on the Global and the this which represents the param context. This follows HTML5 Array.filter syntax. To access closure variables you need to pass them via the param. Some examples
inside an event handler, the longest syntax is:
$('#myelement').click(function() {
var element = this;
context.set.filter(function(it) { return it.id_local == this.id; },
{ id: element.id});
});
you can also however omit the this to reference the params as of JayData 1.2 and also use string predicates
$('#myelement').click(function() {
var element = this;
context.set.filter("it.id_local == id", { id: element.id});
});
Note that in the string syntax the use of it to denote the lambda argument is mandatory.
In JayData 1.3 we will have an even simplex calling syntax
$('#myelement').click(function() {
var element = this;
context.set.filter("it.id_local", "==", element.id);
});
In the filter you should pass an object which is the this object, like this:
.filter(function(){},{idABorrar: foo})
foo can be const or any variable which is in scope.
The .filter() function takes an optional 2nd parameter which is assigned to this inside of the first parameter function.
So you can modify your code like so :
function db_borrarServer(idABorrar){
serversDB.servidores
.filter(function(elementoEncontrado) {
return elementoEncontrado.id_local == this;
}, idABorrar)
.forEach(function(elementoEncontrado){
console.log('Starting to remove ' + elementoEncontrado.nombre);
serversDB.servidores.remove(elementoEncontrado);
serversDB.saveChanges();
});
}
Let me know how you go - I'm very new to jaydata too and I've also been going a bit crazy trying to get my head into this paradigm.
But I came across your question trying to solve the same issue, and this is how I resolved it for me.
My question is simple:
I'm passing a function to some other function to be call later (sample callback function), the question is when, why and what is the best practice to do it.
Sample:
I have the xxx() function, and I have to pass it, as I show you below in the window.onload event.
What is the best practice and why? There is any performance aspect or why should I choose to use call or bind to call this function
function xxx(text)
{
var div = document.createElement("div");
div.innerHTML = text + " - this: " + this.toString();
document.body.appendChild(div)
}
function callFunction(func)
{
func("callFunction");
}
function callUsingCall(func)
{
func.call(this, ["callUsingCall"]);
}
function callUsingBind(func)
{
func.call(this, ["callUsingCall"]);
}
window.onload = function(){
callFunction(xxx);
callUsingCall(xxx);
callUsingBind(xxx.bind(document));
}
Thank you,
Sebastian P.
I don't think there's any "best" practise.
You use call if the function you're calling cares what this is.
You use bind if you want to ensure that the function can only be called with the specified value of this.
[There's some overhead to both, i.e. at least one depth of function calls / scope]
Otherwise you just call the function.
Simples :)
The this object is the context of the function. It's like you make a machine that something for you, and the this object would be the place that the machine works in, like your house. You can move it as you like.
We have 4 ways setting this objects.
Calling the function that is not a method:
fn(someArguments)
This way the this object is set to null or probably the window object.
Calling the function as a method:
someObject.fn(someArguments)
In this case the this object will point to someObject and it's mutable.
Calling with call or apply methods of the function.
fn.call(anotherObject, someArguments)
someObject.call(anotherObject, someArguments)
someObject.apply(anotherObject, [someArguments])
In this case the this object will point to someObject here. You are forcing it to have another context, when calling it.
Binding a the function
var fn2 = fn.bind(anotherObject, someArguments)
This will create another function that is binded to that this object we gave it(anotherObject). No matter how you call it, the this object is going to be the same.
Use Cases
Now you can do some tricky stuff knowing this. The reason that why we have it here(I think it came first from C++) is that methods of an object need to access to their parent. The this object provides the access.
var coolObject = {
points : ['People are amazing'],
addPoint : function (p) { this.points.push(p) }
}
So if you do the following it won't work:
var addPoint = coolObject.addPoint;
addPoint('This will result in an error');
The error will be thrown because the this object is not our coolObject anymore and doesn't have the points property. So at times like this, you can something like this:
var addPoint = coolObject.addPoint;
addPoint.call({points : []}, 'This is pointless');
This is pointless, but the function will work, even the this object is not what its supposed to be.
var anotherCoolObject = {
points : ['Im a thief!'],
addPoint : coolObject.addPoint
}
anotherCoolObject.addPoint('THIS IS CALL STEALING');
Still the function will work if you call it like that, since the this object will point to anotherCoolObject which has the points property.
The most popular use case I've seen is slicing the arguments object:
function returnHalf() {
return [].slice.call(arguments, 0, arguments.length / 2);
}
returnHalf('Half', 'is', 'not', 'awesome');
// >> [Half', 'is']
So you see, arguments object is not an instanceof array. If we do arguments.slice(...) then you're gonna be killed by the compiler. But here we use the array's method on arguments object, since it's array like.
Sometimes you don't want your function context to be changed or you wanna add your own arguments, you use bind.
For example when you add a listener for an event with jquery, when jquery calls your function, the this object will be the element. But sometimes you wanna do tricky stuff and change it:
var myElement = {
init : function () {
$(this.element).click(this.listener.bind(this));
},
view : "<li>${Name}</li>",
name : 'ed',
element : $('#myelement'),
listener : function () {
this.element.append($.tmpl( this.view, this ));
}
}
myElement.init();
So here, you bind it to the myElement, so you can have access to the object properties to render the view. Another examples would be the following:
for (var i = 0; i < 10; i++) {
setTimeout(function () {console.log(i)}, 10)
}
// All of them will be 10.
for (var i = 0; i < 10; i++) {
setTimeout((function () {console.log(this.i)}).bind({ i : i }, 10)
}
If you have put an asynchronous function call in a loop, by the time the callback is called, the loop is finished, and the counter have reached the end, you can use bind to cleanly bind the current counter to your callback.
Another good use case of it, that I use a lot is when passing my functions with arguments to async module, without creating closures.
async.parallel({
writeFile : function (cb) {
fs.writeFile('lolz.txt', someData, cb);
},
writeFile2 : function (cb) {
fs.writeFile('lolz2.txt', someData, cb);
}
}, function (err){
console.log('finished')
});
async.parallel({
writeFile : fs.writeFile.bind(fs, 'lolz.txt', someData),
writeFile2 : fs.writeFile.bind(fs, 'lol2z.txt', someData),
}, function (err){
console.log('finished')
});
These two implementations are identical.
Performance
Just check these out:
http://jsperf.com/bind-vs-call2
http://jsperf.com/js-bind-vs-closure/2
http://jsperf.com/call-vs-closure-to-pass-scope/10
bind has a big performance overhead comparing to other types of calling, but make sure you don't sacrifice performance with maintainability with pre-mature optimizations.
Also you can have a look at this article.
I have this code:
_trackit: function(){
for(var key in this.items.sublinks){
switch(key){
case 'shoes':
for(var innerkey in this.items.sublinks[key]){
(function(){
$(innerkey).observe('click', (function(e){
Event.stop(e);
someClass.click_link( this.items.sublinks[key][innerkey],false)
}));
)(this);
}
break;
}
}
}
The hash I am passing in has a size of 2. But as you would guess both of the links (since the hash maps to links), are passing the last hash value to come through (someClass.click_link <- in here this value, this.item.sublinks[key][innerkey]).
I've tried using an innerfuction etc... but something is messing up. If I go to "inner function deep", then this.items returns undefined.
Any help?
Since you're passing this in as an argument, you just need to create a parameter for it — call it, say, _this — and then you can refer to _this instead of this inside the function:
(function(_this, innerkey){
$(innerkey).observe('click', (function(e){
Event.stop(e);
someClass.click_link( _this.items.sublinks[key][innerkey],false)
}));
)(this, innerkey);
(There are other ways as well, but the above seems to be the way you were going for when you passed this in as an argument? And it's a perfectly respectable way to do it.)
Edited to add: Per Rob W's comment, I've edited the above to add innerkey as a parameter as well, since otherwise the inner function(e){...} expression will refer to the same innerkey variable as the outer function — a variable which, as a loop variable, is likely to have changed by the time the inner function actually runs. Passing it as a parameter gives the inner expression a new innerkey variable that's equal to what innerkey was when the inner function was created.
As others mentioned, you need to have an argument to receive the "this" you are passing. You will also need to pass copies of the "key" and "innerkey" variables, in order to avoid the closures inside for loops bug.
var make_event_listener = function(that, key, innerKey){
return function(e){
Event.stop(e);
someClass.click_link( that.items.sublinks[key][innerkey], false)
};
};
//...
for(var innerkey in this.items.sublinks[key]){
$(innerkey).observe('click', make_event_listener(this, key, innerKey) );
}
//...
OF course, you can use an anonymous version of make_event_listener instead but I find this way more readable.
The second call to "this" references the actual element being clicked. Change it to:
_trackit: function () {
var self = this;
for (var key in this.items.sublinks) {
switch (key) {
case 'shoes':
for (var innerkey in this.items.sublinks[key]) {
(function () {
$(innerkey).observe('click', (function (e) {
Event.stop(e);
someClass.click_link(self.items.sublinks[key][innerkey], false)
}));)(this);
}
break;
}
}
}
}
I have a function, a(), that I want to override, but also have the original a() be performed in an order depending on the context. For example, sometimes when I'm generating a page I'll want to override like this:
function a() {
new_code();
original_a();
}
and sometimes like this:
function a() {
original_a();
other_new_code();
}
How do I get that original_a() from within the over-riding a()? Is it even possible?
Please don't suggest alternatives to over-riding in this way, I know of many. I'm asking about this way specifically.
You could do something like this:
var a = (function() {
var original_a = a;
if (condition) {
return function() {
new_code();
original_a();
}
} else {
return function() {
original_a();
other_new_code();
}
}
})();
Declaring original_a inside an anonymous function keeps it from cluttering the global namespace, but it's available in the inner functions.
Like Nerdmaster mentioned in the comments, be sure to include the () at the end. You want to call the outer function and store the result (one of the two inner functions) in a, not store the outer function itself in a.
The Proxy pattern might help you:
(function() {
// log all calls to setArray
var proxied = jQuery.fn.setArray;
jQuery.fn.setArray = function() {
console.log( this, arguments );
return proxied.apply( this, arguments );
};
})();
The above wraps its code in a function to hide the "proxied"-variable. It saves jQuery's setArray-method in a closure and overwrites it. The proxy then logs all calls to the method and delegates the call to the original. Using apply(this, arguments) guarantees that the caller won't be able to notice the difference between the original and the proxied method.
Thanks guys the proxy pattern really helped.....Actually I wanted to call a global function foo..
In certain pages i need do to some checks. So I did the following.
//Saving the original func
var org_foo = window.foo;
//Assigning proxy fucnc
window.foo = function(args){
//Performing checks
if(checkCondition(args)){
//Calling original funcs
org_foo(args);
}
};
Thnx this really helped me out
You can override a function using a construct like:
function override(f, g) {
return function() {
return g(f);
};
}
For example:
a = override(a, function(original_a) {
if (condition) { new_code(); original_a(); }
else { original_a(); other_new_code(); }
});
Edit: Fixed a typo.
Passing arbitrary arguments:
a = override(a, function(original_a) {
if (condition) { new_code(); original_a.apply(this, arguments) ; }
else { original_a.apply(this, arguments); other_new_code(); }
});
The answer that #Matthew Crumley provides is making use of the immediately invoked function expressions, to close the older 'a' function into the execution context of the returned function. I think this was the best answer, but personally, I would prefer passing the function 'a' as an argument to IIFE. I think it is more understandable.
var a = (function(original_a) {
if (condition) {
return function() {
new_code();
original_a();
}
} else {
return function() {
original_a();
other_new_code();
}
}
})(a);
The examples above don't correctly apply this or pass arguments correctly to the function override. Underscore _.wrap() wraps existing functions, applies this and passes arguments correctly. See: http://underscorejs.org/#wrap
In my opinion the top answers are not readable/maintainable, and the other answers do not properly bind context. Here's a readable solution using ES6 syntax to solve both these problems.
const orginial = someObject.foo;
someObject.foo = function() {
if (condition) orginial.bind(this)(...arguments);
};
I had some code written by someone else and wanted to add a line to a function which i could not find in the code. So as a workaround I wanted to override it.
None of the solutions worked for me though.
Here is what worked in my case:
if (typeof originalFunction === "undefined") {
originalFunction = targetFunction;
targetFunction = function(x, y) {
//Your code
originalFunction(a, b);
//Your Code
};
}
I've created a small helper for a similar scenario because I often needed to override functions from several libraries. This helper accepts a "namespace" (the function container), the function name, and the overriding function. It will replace the original function in the referred namespace with the new one.
The new function accepts the original function as the first argument, and the original functions arguments as the rest. It will preserve the context everytime. It supports void and non-void functions as well.
function overrideFunction(namespace, baseFuncName, func) {
var originalFn = namespace[baseFuncName];
namespace[baseFuncName] = function () {
return func.apply(this, [originalFn.bind(this)].concat(Array.prototype.slice.call(arguments, 0)));
};
}
Usage for example with Bootstrap:
overrideFunction($.fn.popover.Constructor.prototype, 'leave', function(baseFn, obj) {
// ... do stuff before base call
baseFn(obj);
// ... do stuff after base call
});
I didn't create any performance tests though. It can possibly add some unwanted overhead which can or cannot be a big deal, depending on scenarios.
So my answer ended up being a solution that allows me to use the _this variable pointing to the original object.
I create a new instance of a "Square" however I hated the way the "Square" generated it's size. I thought it should follow my specific needs. However in order to do so I needed the square to have an updated "GetSize" function with the internals of that function calling other functions already existing in the square such as this.height, this.GetVolume(). But in order to do so I needed to do this without any crazy hacks. So here is my solution.
Some other Object initializer or helper function.
this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(
this.viewerContainer)
var viewer = this.viewer;
viewer.updateToolbarButtons = this.updateToolbarButtons(viewer);
Function in the other object.
updateToolbarButtons = function(viewer) {
var _viewer = viewer;
return function(width, height){
blah blah black sheep I can refer to this.anything();
}
};
Not sure if it'll work in all circumstances, but in our case, we were trying to override the describe function in Jest so that we can parse the name and skip the whole describe block if it met some criteria.
Here's what worked for us:
function describe( name, callback ) {
if ( name.includes( "skip" ) )
return this.describe.skip( name, callback );
else
return this.describe( name, callback );
}
Two things that are critical here:
We don't use an arrow function () =>.
Arrow functions change the reference to this and we need that to be the file's this.
The use of this.describe and this.describe.skip instead of just describe and describe.skip.
Again, not sure it's of value to anybody but we originally tried to get away with Matthew Crumley's excellent answer but needed to make our method a function and accept params in order to parse them in the conditional.