can't get function's global execution context variable in runtime - javascript

i guess this is a pure vanilla's javascript issue.
i needed to override a function showDatepicker , i did it this way :
const Base = (Handsontable.editors.DateEditor as any).prototype as any;
const DateEditorHelper = Base.extend();
DateEditorHelper.prototype.showDatepicker = function (event: any[]) {
Base.showDatepicker.apply(this, event)
this.$datePicker.config(this.getDatePickerConfig());
var offset = this.TD.getBoundingClientRect();
var dateFormat = this.cellProperties.dateFormat || this.defaultDateFormat;
var datePickerConfig = this.$datePicker.config();
var dateStr = void 0;
var isMouseDown = this.instance.view.isMouseDown();
var isMeta = event ? (0, _unicode.isMetaKey)(event.keyCode) : false;
this.datePickerStyle.top = offset.top >= $(window).height() - 224 ? window.pageYOffset + offset.top - 224 + (0, _element.outerHeight)(this.TD) + 'px' : window.pageYOffset + offset.top + (0, _element.outerHeight)(this.TD) + 'px';
this.datePickerStyle.left = window.pageXOffset + offset.left + 'px';
this.$datePicker._onInputFocus = function () { };
datePickerConfig.format = dateFormat;
if (this.originalValue) {
dateStr = this.originalValue;
if ((0, _moment2.default)(dateStr, dateFormat, true).isValid()) {
this.$datePicker.setMoment((0, _moment2.default)(dateStr, dateFormat), true);
}
// workaround for date/time cells - pikaday resets the cell value to 12:00 AM by default, this will overwrite the value.
if (this.getValue() !== this.originalValue) {
this.setValue(this.originalValue);
}
if (!isMeta && !isMouseDown) {
this.setValue('');
}
} else if (this.cellProperties.defaultDate) {
dateStr = this.cellProperties.defaultDate;
datePickerConfig.defaultDate = dateStr;
if ((0, _moment2.default)(dateStr, dateFormat, true).isValid()) {
this.$datePicker.setMoment((0, _moment2.default)(dateStr, dateFormat), true);
}
if (!isMeta && !isMouseDown) {
this.setValue('');
}
} else {
// if a default date is not defined, set a soft-default-date: display the current day and month in the
// datepicker, but don't fill the editor input
this.$datePicker.gotoToday();
}
this.datePickerStyle.display = 'block';
this.$datePicker.show();
}
It's actually the original function's code in which i made some small modification.
i thought the function's inner code variables will be evaluated in runtime (i'm not talking about the inner function scope variables as its arguments or variables declared in it but about the global variables to the execution context).
Before the function get executed there are no errors at all (when the browser reads the function , it doesn't complain about that some variables are undefined) but when it runs , i got this error :
Uncaught ReferenceError: _unicode is not defined
at eval (eval at DateEditorHelper.showDatepicker (module.js?v=64fd5db96274:40281), <anonymous>:1:1)
at e.DateEditorHelper.showDatepicker (module.js?v=64fd5db96274:40281)
The overriden function is running in the same context as where the original function should runs , i don't know why a global variable is undefined.
The original function is a handsontable built-in editor (datePicker). The overriding idea i got it from this thread and this

You say that you copied the code from the original function and made minor changes. The problems seems to be that you're using a variable named _unicode. Are you defining that variable?
When replacing a method's code with the 'original' code modified, you must made sure that any other variable/function referenced by the old code is also copied.
You must take into account that the original method was defined in another context. Probably, the author didn't mean for this class to be derived, or to have its methods overriden.
The advantage of modules (or IIFEs) is that you can define a public API while encapsulating the private parts of the implementation. Of course, this means that overriding methods or functions is much more difficult.
In this case, the variable _unicode is clearly intended to be part of the private implementation. The fact that its name follows the convention of starting with an underscore is almost proof of that. It probably is defined in the same module as DatePickerHelper, or imported from another, but in any case I'm almost sure it is not exported, so you cannot have access to it and your code fails.
For your override to work, you must either change the code to avoid using that _unicode variable, or define it yourself the same way it is done in the original code. Of course, depending of how it is defined you may end up having to 'copy' lots of that code, but that's an issue that any JavaScript programmer who has ever tried to override a method from an external library has suffered.
Let's see an example of this 'private implementation':
(function() {
// this is a function I want to keep private.
function giveMeHello() {
return 'hello, ';
}
// this is the class I want to share
class Greeting {
greet(name) {
console.log(giveMeHello() + name);
}
}
window.Greeting = Greeting;
})();
const greet1 = new Greeting();
greet1.greet('Oscar'); // outputs 'hello, Oscar'.
// As a consumer of Greeting, I don't like the way if greets people. I want the name to be in uppercase
// implementation is practically identical to original code
Greeting.prototype.greet = function() {
console.log(giveMeHello() + name.toUpperCase());
};
// Let's use it!
greet1.greet('John'); // Oh! Error! giveMeHello is not defined!
As you see, in this example I doing the same you are. But my implementation relies, just as the original one, on the giveMeHello function. But giveMeHello is no a global or public function. I haven't got access to it from the point in which I am overriding the function. Therefore, when I execute the method, it fails.
If now I just copy the giveMeHello function before overriding the method, it will work.
Do you get it now? If you don't, I suggest you to read more about scopes in JavaScript, something that is beyond the purpose of StackOverflow.

Related

How to update a variable that depends on another variable in a function?

In the sample code below, note that the value of the variable dependent depends on the variable prereq. When the function changePrereq is called, it changes the value of prereq. This change is shown if logged, but it isn't reflected in the value of dependent. Instead, when dependent is put into a span, it shows Some text - undefined.
How can I have dependent change depending on the value of prereq?
P.S. Thanks everyone for the advice. For myself, I chose the answer from "ztcollazo" as the right decision.
"outis" - Thank you for your explanations. I will definitely pay attention to your recommendations and study them in more detail!
var display = document.getElementById('text'),
prereq,
message = "Some text - " + prereq;
function updateDisplay() {
display.innerHTML = message;
console.log(prereq);
}
function changePrereq() {
prereq = "I am some text.";
updateDisplay();
}
<p><span id="text"></span></p>
<button onclick="changePrereq()">Click</button>
The problem is that changeMyText doesn't update when someText does. You need to define changeMyText inside of the changeTextFunc function and then pass someText as a parameter.
Example:
var myText = document.getElementById('text');
var someText1;
var m1 = 1;
function changeTextFunc(someText, m) {
var changeMyText = "Some text - " + someText;
if (m > 0) {
myText.innerHTML = changeMyText;
} else {
console.log('m < 0');
}
}
function changeText() {
someText1 = "I a'm some text.";
changeTextFunc(someText1, m1);
}
<div>
<button onclick="changeText()">Click</button>
<p id="text"></p>
</div>
move changeMyText variable into changeTextFunc function.
the code will looks like this
function changeMyText(m){
var changeMyText = "Some text - " + someText1;
if (m > 0) {
myText.innerHTML = changeMyText;
} else {
console.log('m < 0');
}
}
If you want a variable to change based on another, you must set its value after the other is changed. There are various approaches, with various implementations. You can break it down into different aspects for the change:
what:
globals (note: avoid global variables in production, and use sparingly in other contexts for the practice)
locals
objects
plain methods
getter/setter methods
where:
inline, at the site a variable is referred to
in a separate function created for the responsibility
when:
the prerequisite variable is changed
the dependent variable is used
Some of the above options from different aspects aren't intended to be combined, or can't be combined. For example, 1.3 (objects) is intended to go with 2.2 (separate functions), and 1.3.2 (getters/setters) requires 2.2, since object getters & setters are functions (2.2 basically means "use a getter or setter", though not necessarily using getter/setter syntax). You might be able to think of other aspects, or other possibilities for the above aspects.
ztcollazo shows a solution that uses a global for the prerequisite (1.1), a local for the dependent (1.2) and updates inline (2.1) when the dependent is used (3.2). If the line in changeTextFunc setting changeMyText were instead move to changeText (and a global used), you'd have 1.1 + 2.1 + 3.1.
For some more example implementations, examine the following. It illustrates four different options from the above, noted by comments.
var display = document.getElementById('output'),
dependent, prereq;
/* options 1.1, 2.2, 3.1: global, separate function, prereq change */
function setPrereq(value) {
prereq = value;
dependent = "global prereq setter: " + prereq;
}
function updateDisplayFromVariable() {
display.innerText = dependent;
}
function changePrereq_updateWhenSet(value="setter") {
setPrereq(value);
updateDisplayFromVariable();
}
/* options 1.1, 2.2, 3.2: global, separate function, dependent used */
function getDependent(value) {
return dependent = "global dependent getter: " + prereq;
}
function updateDisplayFromGetter() {
display.innerText = getDependent();
}
function changePrereq_updateWhenUsed(value="inline, no setter") {
prereq = value;
updateDisplayFromGetter();
}
/* options 1.3.2, 2.2: (local) object getter/setter */
/* wrapped in self-called function to prevent polluting global namespace */
var dependency = (function () {
let display = document.getElementById('output'),
/* options 1.3.2, 2.2, 3.2: (local) object getter, dependent used */
inGetter = {
prereq: 'initial',
/* note: `dependent` is entirely synthetic */
get dependent() {
return "object's dependent getter: " + this.prereq;
},
},
/* options 1.3.2, 2.2, 3.1: (local) object setter, prereq changed */
inSetter = {
/* note: when using setter, can't use same name for the
* backing property; instead, must also define getter. */
_prereq: 'initial',
get prereq() {
return this._prereq;
},
set prereq(value) {
this._prereq = value;
this.dependent = "object's prereq setter: " + value;
},
};
function updateDisplay(from) {
display.innerText = from.dependent;
}
/* expose 1.3.2, 2.2, 3.1 */
function whenSet(value) {
inSetter.prereq = value;
updateDisplay(inSetter);
}
/* expose 1.3.2, 2.2, 3.2 */
function whenUsed(value) {
inGetter.prereq = value;
updateDisplay(inGetter);
}
return {whenSet, whenUsed};
})();
<button onclick="changePrereq_updateWhenSet('thimbles')">Use global setter</button>
<button onclick="changePrereq_updateWhenUsed('care')">Use global getter</button>
<button onclick="dependency.whenSet('forks')">Use object setter</button>
<button onclick="dependency.whenUsed('hope')">Use object getter</button>
<p><span id="output"></span></p>
As with any design, the above have advantages and disadvantages, but using object setters/getters (1.3.2) should be preferred, as it's the most robust approach. Using standalone functions (not getters/setters) and updating inline are both more brittle as a programmer may fail to use them somewhere, instead assigning & referencing variables directly. Updating inline is also less maintainable, as any changes will have to be made on every line that performs the update. Global variables have their own issues, such as:
limited code reuse in a module (note how updateDisplay(from) works for two different cases, whereas changePrereq_updateWhenSet and changePrereq_updateWhenUsed each require different display functions), and
inflexibility (i.e. composing existing functions for new behaviors is much more limited; in other words, this limits code reuse for client code),
naming collisions when different modules use the same globals, causing them to stomp on each other.
As for whether to update the dependent in the prerequisite's setter (1.3.2 + 2.2 + 3.1) or to use a getter for the dependent with no backing property (in some circles, this is known as a "synthetic property") depends on other requirements (basically, whether the dependent be allowed to be assigned values independent of the prerequisite). You could, for instance, use getters & setters for both properties.

How can I provide protection and confidentiality?

I want to restrict access to certain things in the JavaScript language from the outside. I've done some research on this, but I haven't been able to get anything I want. I know the underscore doesn't provide complete protection. When I try to reach from outside, I can easily reach. I'm going to write a sample code.
function Car(){
this._mileage = 0;
}
Car.prototype.drive = function(miles){
if(typeof miles == 'number' && miles > 0){
this._mileage += miles;
}else{
throw new Error("Sadece pozitif sayılar girin");
}
};
Car.prototype.readMileage = function(){
return this._mileage;
}
var hondo = new Car();
console.log('old: '+hondo._mileage);
hondo._mileage = 100;
console.log('new: '+hondo._mileage);
As you can see: Although I used underscores, I could easily access from outside the classroom.
Another method
I found a method in my research. But I don't quite understand that either.
var Car = (function(){
var _ = PrivateParts.createKey(); // createKey = ?
function Car(mileage){
_(this).mileage = mileage;
}
Car.prototype.drive = function(miles){
if( typeof miles == 'number' && miles > 0){
_(this).mileage += miles;
}else{
throw new Error('drive only accepts positive numbers');
}
}
Car.prototype.readMileage = function(){
return _(this).mileage;
}
return Car;
}());
Your second code is generally on the right track, though you need to define privateParts as something first. It also seems a bit too complicated at the moment.
The idea is to save the variable in a closure; due to normal scoping rules, a variable can't be accessed outside where it's defined:
const fn = (() => {
const foo = 'foo';
return () => 'foo is: ' + foo;
})();
// at this point, the contents of the "foo" variable are not visible to the outside,
// you can only call the deliberately exposed function:
console.log(fn());
Similarly, with a class, you can save all properties you want to keep private in an Map indexed by the instance used: keep the Map scoped to just the class, and not the outside, and everything you put on the Map won't be visible to the outside:
const Car = (() => {
const map = new WeakMap();
return class Car {
constructor(mileage) {
map.set(this, { mileage });
}
drive(miles) {
if (typeof miles == 'number' && miles > 0) {
map.get(this).mileage += miles;
} else {
throw new Error('drive only accepts positive numbers');
}
}
readMileage() {
return map.get(this).mileage;
}
}
})();
var hondo = new Car(50);
console.log('old: '+hondo._mileage);
hondo._mileage = 100;
console.log('new: '+hondo._mileage);
console.log(hondo.readMileage());
hondo.drive(100);
console.log('newer: '+hondo._mileage);
console.log(hondo.readMileage());
The Map is basically just an object indexed by each this (each instance of Car). Because its values can only be retrieved inside the Car closure, it's an effective way of making sure the information is not exposed to the outside.
That said, this doesn't prevent clients from looking at your source code - no client-side code is truly private. If you have sensitive information, you should only send it to the client in the first place if they have to know it. Using a technique like this will not prevent the client from looking at your code and possibly intercepting information sent. (Nefarious scripts can do something similar, especially if given the opportunity to run before your script runs.) So what this implements isn't so much confidential, so much as it provides reasonable but not airtight restrictions on how other well-behaved scripts can access data.
It's called an IIFE (Immediately Invoked Function Expression) and it means that the private key you make with PrivateParts.createKey will never ever be accessible outside of the function, because the code inside the IIFE is run, then it ends. Because of the way you have defined it, you now have a completely unique key that cannot be accessed from anywhere. That being said, it's still very insecure to do any key or encryption work on the client side - use PHP, Node.JS, or another server-side language to fully protect your data.

Difficulty Understanding Javascript Code Snippet

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!

need help understanding closures usage in this code

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...

Force missing parameters in JavaScript

When you call a function in JavaScript and you miss to pass some parameter, nothing happens.
This makes the code harder to debug, so I would like to change that behavior.
I've seen
How best to determine if an argument is not sent to the JavaScript function
but I want a solution with a constant number of typed lines of code; not typing extra code for each function.
I've thought about automatically prefixing the code of all functions with that code, by modifying the constructor of the ("first-class") Function object.
Inspired by
Changing constructor in JavaScript
I've first tested whether I can change the constructor of the Function object, like this:
function Function2 () {
this.color = "white";
}
Function.prototype = new Function2();
f = new Function();
alert(f.color);
But it alerts "undefined" instead of "white", so it is not working, so I've don't further explored this technique.
Do you know any solution for this problem at any level? Hacking the guts of JavaScript would be OK but any other practical tip on how to find missing arguments would be OK as well.
If a function of yours requires certain arguments to be passed, you should check for those arguments specifically as part of the validation of the function.
Extending the Function object is not the best idea because many libraries rely on the behavior of defaulting arguments that are not passed (such as jQuery not passing anything to it's scoped undefined variable).
Two approaches I tend to use:
1) an argument is required for the function to work
var foo = function (requiredParam) {
if (typeof requiredParam === 'undefined') {
throw new Error('You must pass requiredParam to function Foo!');
}
// solve world hunger here
};
2) an argument not passed but can be defaulted to something (uses jQuery)
var foo = function (argumentObject) {
argumentObject = $.extend({
someArgument1: 'defaultValue1',
someArgument2: 'defaultValue2'
}, argumentObject || {});
// save the world from alien invaders here
};
As others have said, there are many reasons not to do this, but I know of a couple of ways, so I'll tell you how! For science!
This is the first, stolen from Gaby, give him an upvote! Here's a rough overview of how it works:
//example function
function thing(a, b, c) {
}
var functionPool = {} // create a variable to hold the original versions of the functions
for( var func in window ) // scan all items in window scope
{
if (typeof(window[func]) === 'function') // if item is a function
{
functionPool[func] = window[func]; // store the original to our global pool
(function(){ // create an closure to maintain function name
var functionName = func;
window[functionName] = function(){ // overwrite the function with our own version
var args = [].splice.call(arguments,0); // convert arguments to array
// do the logging before callling the method
if(functionPool[functionName].length > args.length)
throw "Not enough arguments for function " + functionName + " expected " + functionPool[functionName].length + " got " + args.length;
// call the original method but in the window scope, and return the results
return functionPool[functionName].apply(window, args );
// additional logging could take place here if we stored the return value ..
}
})();
}
}
thing(1,2 ,3); //fine
thing(1,2); //throws error
The second way:
Now there is another way to do this that I can't remember the details exactly, basically you overrride Function.prototype.call. But as it says in this question, this involves an infinite loop. So you need an untainted Function object to call, this is done by a trick of turning the variables into a string and then using eval to call the function in an untainted context! There's a really great snippet out the showing you how from the early days of the web, but alas I can't find it at the moment. There's a hack that's required to pass the variables properly and I think you may actually lose context, so it's pretty fragile.
Still, as stated, don't try and force javascript to do something against its nature, either trust your fellow programmers or supply defaults, as per all the other answers.
You can imitate something like Python’s decorators. This does require extra typing per function, though not extra lines.
function force(inner) {
return function() {
if (arguments.length === inner.length) {
return inner.apply(this, arguments);
} else {
throw "expected " + inner.length +
" arguments, got " + arguments.length;
}
}
}
var myFunc = force(function(foo, bar, baz) {
// ...
});
In general this sounds like a bad idea, because you’re basically messing with the language. Do you really forget to pass arguments that often?
You could use the decorator pattern. The following decorator allows you to specify minimum and maximum number of arguments that need to be passed and an optional error handler.
/* Wrap the function *f*, so that *error_callback* is called when the number
of passed arguments is not with range *nmin* to *nmax*. *error_callback*
may be ommited to make the wrapper just throw an error message.
The wrapped function is returned. */
function require_arguments(f, nmin, nmax, error_callback) {
if (!error_callback) {
error_callback = function(n, nmin, nmax) {
throw 'Expected arguments from ' + nmin + ' to ' + nmax + ' (' +
n + ' passed).';
}
}
function wrapper() {
var n_args = arguments.length;
console.log(n_args, nmin, nmax);
console.log((nmin <= 0) && (0 <= nmax));
if ((nmin <= n_args) && (n_args <= nmax)) {
return f.apply(this, arguments);
}
return error_callback(n_args, nmin, nmax);
}
for (e in f) {
wrapper[e] = f[e];
}
return wrapper;
}
var foo = require_arguments(function(a, b, c) {
/* .. */
}, 1, 3);
foo(1);
foo(1, 2);
foo(1, 2, 3);
foo(1, 2, 3, 4); // uncaught exception: Expected arguments from 1 to 3 (4 passed).
foo(); // uncaught exception: Expected arguments from 1 to 3 (0 passed).

Categories

Resources