I've written a little script that converts any given URI-like string into a DOM object similar to that received by window.location. This is achieved by using the DOM to create an anchor element, assigning the passed string to its href property, and then copying out all static properties that are present in both anchor elements and the window.location element.
I later noticed that window.location is an instanceof the mysterious Location object, but attempting to invoke Location is illegal. For fun, I decided to override the Location object and change my function's API to match native DOM constructor style.
One of the nice (or horrible, depending on perspective) things about DOM objects like Location and Date is their non-standard implementation of toString, which appears to be invoked behind the scenes when certain operators are invoked:
var x = window.location + '?querystring' // => 'http://stackoverflow.com/questions/ask?querystring';
I can't seem to emulate this kind of behaviour.
My first attempt was:
Location.prototype.toString = function toString(){ return this.href };
This is the only solution I've found which emulates window.location.toString() direct invocation, but obviously I've lost all binding to the original prototype internals, so returning the href on explicit invocation is all it does.
So I thought I needed to apply my custom Location to the native toString behaviour of Location, but:
Location.prototype.toString = function toStringClosure(){
// Can't use `Function.prototype.bind` because we need
// the closure to invoke `this`. Javascript is awesome.
return ( new Location() ).toString.call( this );
}
…will tell you that executing Location is illegal or invalid. Of course. But what about:
Location.prototype.toString = function toStringClosure(){
return ( new Date() ).toString.call( this );
}
No, this is not an instance of Date. This implies extra-special privileges in native objects, or maybe just a nice opaque wrapper around "I tried to look for other Date internals that Date.prototype.toString actually aliases to, but couldn't find them".
However, querying the prototype without executing the Date or Location constructors reveals something else:
Location.prototype.toString = function toStringClosure(){
return Location.prototype.toString.call( this );
}
Namely, Function.prototype.toString is not generic. Yeah I know, that's why I specifically invoked the non-generic Location variety. This leads me to believe that the internals of these objects don't actually play by the normal rules of inheritance, or indeed Javascript execution (after all, direct property assignment with window.location = x will implicitly execute window.location.assign( x ) — I suppose this is similar to setAttribute with certain nodes, but they remain essentially read-write).
So: is there any way I can emulate the magical string coercion displayed by direct operations on Date and Location objects?
And: how do the last 2 snippets of code play out internally? Are there internal relationships and code properties at work there that cannot be expressed in pure JS?
At some point in my investigations I got lax. My first attempt was:
Location.prototype.toString = function toString(){ return this.href };
…And it turns out this is all that is necessary: when an object is an operand in an operation in which the other operand is not of the same type, the following properties will be invoked in sequence to see if an operation is feasible:
valueOf
toString
Javascript looks for the toString method, finds it and executes it and attempts the operation there. So in fact, under my current revision, if I run:
new Location('/root') + '?query=string';
…I will get:
"http://stackoverflow.com/root?query=string"
Sorted!
Related
I'm looking to see how the typeof operator in JavaScript knows that an object is a function.
To be precise, I'm wondering how I can take the function 'body' and reverse engineer it to determine what arguments it expects. The arguments property seemed close, but is only available within the evaluated function.
Neither uneval() or toSource() appear to do quite what I want, in addition to being obsolete.
The specification shows that:
Objects that do not implement [[Call]] are objects
Objects that do implement [[Call]] are functions
([[Call]] is an "internal property" of objects - it's not exposed directly to interactable running JavaScript)
So anything that can be ()d is a function. This will even include Proxies, since proxies can be called as if they were functions.
For the other question:
I'm wondering how I can take the function 'body' and reverse engineer it to determine what arguments it expects
The simplest method would be to turn the function into a string and use a regex to parse the parameter list:
function sum(a, b) {
return a + b;
}
const argList = String(sum).match(/\((.*)\)/)[1];
console.log(argList.split(/,\s*/)); // depending on how complicated the list is
// you may need to make the above pattern more elaborate
Background
I am struggling to create a function that takes a timestamp in ms from JSON and to convert it to a human-readable format. I attempted alert(Date(jsonData.timestamp).toISOString()), which resulted in "Date(...).toISOString is not a function".
But in the example for timeformating that I had looked up it worked, soon enough I noted that the pattern to be used is let myDate=new Date(...); alert(myDate.toISOString()). I tried and got an Invalid Date. So for some reason Date() and new Date() interpret the arguments differently.
I thought maybe the value I get from JSON which is a string should be passed in as a Number when I do that I end up with two different dates:
new Date(1594720804236643)); // result differs from thjsut calling Date, without new
new Date("1594720804236643")); //does not work
I figured that surly copy construciton would work and ended up with:
let myDate=Date(jsonData.timestamp);
let myDateObject=new Date(myDate);
alert(myDateObject.toISOString());
While I have a (horrible, ugly) solution, I would like to understand the nuances of new
Actual Question
Where is the difference between MyClass() and new MyClass(), a C++ programming background suggests that the difference is the only whether the object is allocated on the stack or heap. In Javascript, clearly the rules are different. On the one hand the interpretation of arguments changes, on the other hand, the set of functions available on the resulting object is different.
Here's a common pattern for a constructor that, for its own design reasons, wants to behave the same way whether it's invoked with new or not:
function NewIsOptional() {
if (this == null || !(this instanceof NewIsOptional))
return new NewIsOptional();
// normal constructor work
}
That trick works by checking this. If it's not bound (as would be the case if new were missing) or if it's bound to something of the wrong type, the code makes a recursive call via new. That pass through the constructor will see this properly bound to a new object, so it'll proceed to do its normal thing.
Now, not all constructor functions do that. I'm not sure I've ever written one, and I've typed in a lot of code. Some constructors throw an exception if they're not invoked via new. Some, for example the Symbol "constructor", throw an exception if they are invoked with new. Some constructors (like Date or Boolean) do completely different things when they're not invoked with new.
Basically there are no rules. A constructor is a function, and the code in the constructor can do whatever it wants. It can type check the parameter values and decide on different behaviors or decide to throw errors. It can call other functions, manipulate its closure if it was created inside one, and of course do mundane things like initialize object properties (which is the most usual thing to do).
Also, note that how a particular constructor function interprets its arguments, and how it behaves when it is or isn't invoked via new, are two completely orthogonal things. There are no rules for that either. A constructor is free to interpret arguments exactly the same with or without new, or it can interpret them completely differently. There are no fundamental language rules behind any of this.
Eclipse has an option to warn on assignment to a method's parameter (inside the method), as in:
public void doFoo(int a){
if (a<0){
a=0; // this will generate a warning
}
// do stuff
}
Normally I try to activate (and heed) almost all available compiler warnings, but in this case I'm not really sure whether it's worth it.
I see legitimate cases for changing a parameter in a method (e.g.: Allowing a parameter to be "unset" (e.g. null) and automatically substituting a default value), but few situations where it would cause problems, except that it might be a bit confusing to reassign a parameter in the middle of the method.
Do you use such warnings? Why / why not?
Note:
Avoiding this warning is of course equivalent to making the method parameter final (only then it's a compiler error :-)). So this question Why should I use the keyword "final" on a method parameter in Java? might be related.
The confusing-part is the reason for the warning. If you reassign a parameter a new value in the method (probably conditional), then it is not clear, what a is. That's why it is seen as good style, to leave method-params unchanged.
For me, as long as you do it early and clearly, it's fine. As you say, doing it buried deep in four conditionals half-way into a 30-line function is less than ideal.
You also obviously have to be careful when doing this with object references, since calling methods on the object you were given may change its state and communicate information back to the caller, but of course if you've subbed in your own placeholder, that information is not communicated.
The flip side is that declaring a new variable and assigning the argument (or a default if argument needs defaulting) to it may well be clearer, and will almost certainly not be less efficient -- any decent compiler (whether the primary compiler or a JIT) will optimize it out when feasible.
Assigning a method parameter is not something most people expect to happen in most methods. Since we read the code with the assumption that parameter values are fixed, an assignment is usually considered poor practice, if only by convention and the principle of least astonishment.
There are always alternatives to assigning method parameters: usually a local temporary copy is just fine. But generally, if you find you need to control the logic of your function through parameter reassignment, it could benefit from refactoring into smaller methods.
Reassigning to the method parameter variable is usually a mistake if the parameter is a reference type.
Consider the following code:
MyObject myObject = new myObject();
myObject.Foo = "foo";
doFoo(myObject);
// what's the value of myObject.Foo here?
public void doFoo(MyObject myFoo){
myFoo = new MyObject("Bar");
}
Many people will expect that at after the call to doFoo, myObject.Foo will equal "Bar". Of course, it won't - because Java is not pass by reference, but pass by reference value - that is to say, a copy of the reference is passed to the method. Reassigning to that copy only has an effect in the local scope, and not at the callsite. This is one of the most commonly misunderstood concepts.
Different compiler warnings can be appropriate for different situations. Sure, some are applicable to most or all situations, but this does not seem to be one of them.
I would think of this particular warning as the compiler giving you the option to be warned about a method parameter being reassigned when you need it, rather than a rule that method parameters should not be reassigned. Your example constitutes a perfectly valid case for it.
I sometimes use it in situations like these:
void countdown(int n)
{
for (; n > 0; n--) {
// do something
}
}
to avoid introducing a variable i in the for loop. Typically I only use these kind of 'tricks' in very short functions.
Personally I very much dislike 'correcting' parameters inside a function this way. I prefer to catch these by asserts and make sure that the contract is right.
I usually don't need to assign new values to method parameters.
As to best-practices - the warning also avoids confusion when facing code like:
public void foo() {
int a = 1;
bar(a);
System.out.println(a);
}
public void bar(int a) {
a++;
}
You shoud write code with no side effect : every method shoud be a function that doesn't change . Otherwise it's a command and it can be dangerous.
See definitions for command and function on the DDD website :
Function :
An operation that computes and returns a result without observable side effects.
Command : An operation that effects some change to the system (for
example, setting a variable). An
operation that intentionally creates a
side effect.
Question is self explanatory. I know it is possible to extend primitive data types such as string but is it possible to overwrite it?
This is a question that has been asked in an interview.
No, you cannot overwrite anything. EcmaScript defines the primitive types Undefined, Null, Boolean, Number, and String; these are internal and will be used regardless of what you are doing (for example overwriting the global String constructor). Type conversion and evaluation of literals does not rely on any public functions but uses only these internal types and the algorithms specified for them.
Of course, if someone does string coercion with String(myval) instead of ""+myval assigning to the global String variable will have an effect on that code. Any internal use would still point to the "old" function.
If you were talking about prototype objects for the primitive types (when used as objects), those are not overwritable as well. You may extend those objects, but as soon as you assign to e.g. Number.prototype you just have lost a reference to the actual, original number protype object. Example spec for The Number constructor:
The [prototype] of the newly constructed object is set to the original Number prototype object, the one that is the initial value of Number.prototype (15.7.3.1)
Yes (edit: almost). Open up a Javascript console (F12 if you're using Chrome) and type
String = function(){alert('bang!')};
You can overwrite (edit: almost) everything in Javascript — even the window global context! evil.js is a library that uses this trick to rewrite many native objects as possible.
Needless to say, this is extremely dangerous. I performed the String remapping code above, and since writing it down I've caused over 520 Javascript errors (and I've seen 'bang' alerted quite a few times). Native objects are used everywhere, and you shouldn't modify these in case 3rd party code relies on them in ways you don't know about. This is one of the reasons Prototype.js lost popularity — because its extension of native objects would often work against the expectations of other code.
Edit: Factually incorrect assertion that absolutely everything could be overwritten, as pointed out in Bergi's answer. Edits made inline.
You can extend prototypes of native types.
String.prototype.moo = function() {
console.log( 'Moo!' )
};
'Cow says'.moo();
>> "Moo!"
However you cannot directly overwrite constructors of built-in types unless you overwrite the reference to the entire object:
String = function() {
console.log( 'Custom function.' )
};
new String( 'Hello!' );
>> "Custom function."
>> String {} // now you've broken your website ;)
...but still:
'Wat?!'
>> "Wat?!" // you can still create strings by typing letters in quotes
So... the answer is "yes but no". You can mess with native types (Number, Date, String...) but you cannot re-define them entirely from scratch. They're a part of JS engine that you're using (most likely native C++ code) and this brings some limitations.
Possible like this but you must always succeed without side effects.Not good practice.
function Array() {
var obj = this;
var ind = 0;
var getNext = function(x) {
obj[ind++] setter = getNext;
if (x) alert("Data stolen from array: " + x.toString());
};
this[ind++] setter = getNext;
}
var a = ["private stuff"];
// alert("Data stolen from array: private stuff");
I'm currently reading through this jquery masking plugin to try and understand how it works, and in numerous places the author calls the slice() function passing no arguments to it. For instance here the _buffer variable is slice()d, and _buffer.slice() and _buffer seem to hold the same values.
Is there any reason for doing this, or is the author just making the code more complicated than it should be?
//functionality fn
function unmaskedvalue($input, skipDatepickerCheck) {
var input = $input[0];
if (tests && (skipDatepickerCheck === true || !$input.hasClass('hasDatepicker'))) {
var buffer = _buffer.slice();
checkVal(input, buffer);
return $.map(buffer, function(element, index) {
return isMask(index) && element != getBufferElement(_buffer.slice(), index) ? element : null; }).join('');
}
else {
return input._valueGet();
}
}
The .slice() method makes a (shallow) copy of an array, and takes parameters to indicate which subset of the source array to copy. Calling it with no arguments just copies the entire array. That is:
_buffer.slice();
// is equivalent to
_buffer.slice(0);
// also equivalent to
_buffer.slice(0, _buffer.length);
EDIT: Isn't the start index mandatory? Yes. And no. Sort of. JavaScript references (like MDN) usually say that .slice() requires at least one argument, the start index. Calling .slice() with no arguments is like saying .slice(undefined). In the ECMAScript Language Spec, step 5 in the .slice() algorithm says "Let relativeStart be ToInteger(start)". If you look at the algorithm for the abstract operation ToInteger(), which in turn uses ToNumber(), you'll see that it ends up converting undefined to 0.
Still, in my own code I would always say .slice(0), not .slice() - to me it seems neater.
array.slice() = array shallow copy and is a shorter form of array.slice()
Is there any reason for doing this, or is the author just making the code more complicated than it should be?
Yes there may be a reason in the following cases (for which we do not have a clue, on whether they apply, in the provided code):
checkVal() or getBufferElement() modify the content of the arrays passed to them (as second and first argument respectively). In this case the code author wants to prevent the global variable _buffer's content from being modified when calling unmaskedvalue().
The function passed to $.map runs asynchronously. In this case the code author wants to make sure that the passed callback will access the array content as it was during unmaskedvalue() execution (e.g. Another event handler could modify _buffer content after unmaskedvalue() execution and before $.map's callback execution).
If none of the above is the case then, yes, the code would equally work without using .slice(). In this case maybe the code author wants to play safe and avoid bugs from future code changes that would result in unforeseen _buffer content modifications.
Note:
When saying: "prevent the global variable _buffer's content from being modified" it means to achieve the following:
_buffer[0].someProp = "new value" would reflect in the copied array.
_buffer[0] = "new value" would not reflect in the copied array.
(For preventing changes also in the first bullet above, array deep clone can be used, but this is out of the discussed context)
Note 2:
In ES6
var buffer = _buffer.slice();
can also be written as
var buffer = [..._buffer];