JavaScript function gives error when passed `this` as an argument - javascript

function log(this) {
console.log(this);
}
It throws the error Unexpected token this. So why doesn't JavaScript accept this as an argument?

this is a reserved keyword so it can't be used as a variable name.
If you want to override the this value for a function, you can use call or apply.
function log() {
console.log(this);
}
log.apply({ custom: "this value" });

this has special meaning in the language. It's an identifier, but can only be defined automatically in specific situations, never explicitly by the developer.
Other identifiers that are automatically defined can still be defined by the developer, like arguments, undefined and window, though it should be avoided in most cases.
To add clarity, in programming an identifier is a label used by a programmer to reference a value.
In JS, this is indeed a keyword, which, according to ECMAScript semantics, prevents it from being explicitly declared as an identifier. This does not mean that it isn't an identifier at all, which it clearly is since it will always let the programmer reference a value.
So something being a keyword does not mean that it isn't an identifier. It does mean though that in JS, you don't have the option of explicitly declaring an identifier with that name, though other languages do sometimes allow this.

Related

Where do invalid variables go when using JavaScript's with(){} statement?

When using JavaScript's with statement, where do variables that have invalid names go?
var o = {"##$%":1,"test":2}
with(o){
console.log(test)
// Can't do this:
//console.log(##$%)
// Was it not imported, or is it just inaccessible?
}
Can you reference the code in a JavaScript engine as well?
If a property is not a valid identifier, it can't be referenced like an identifier inside with. It's not inaccessible, but your only option is to look up the property on the original object manually, like normal:
var o = {"##$%":1,"test":2}
with(o){
console.log(o['##$%']);
}
This sort of issue is not exclusive to the deprecated with statement. It occurs with the global object as well. Just like a with statement creates an object Environment Record, similarly, all code in a script is, in a sense, implicitly wrapped in a with for the global object (resulting in the global environment record).
So, for exactly the same reasons, when a property which can't be an identifier is on window, eg:
window['###'] = 'foo';
There's no way to get to foo by using a standalone identifier without explicitly referencing window first (or use some other method to get to the global object).
(of course, just like with with, properties which are valid as identifiers on window can be referenced standalone - that's why we can, for example, reference undefined and Array instead of window.undefined and window.Array. This can cause bugs...)
Where do variables […] go?
I think you have this backwards. A with statement doesn't create any variables (like a var declaration would), instead it changes the scope so that any identifier is looked up as a property on the object. Every time you access xyz, it looks if ('xyz' in o) return o.xyz else … - that's why with statements are so slow and deprecated in strict mode.
So there are no "variables that have invalid names" at all. If you used an invalid identifier in the first place, it would have thrown a syntax error and the code wouldn't even run.

using bind method with () function javascript

I have one question, when I use bind with arrow function doesn't work so if there 's anyone can explain it to me.
let username={
email:"test#test",
login:()=>{console.log(this.email);}
};`
when i tap username.login()return undefined also if u tap username.login.bind(username) if there's anyone who can help I will be very thankful.
I m all ears for more info.
Have a read of this from MDN to understand how arrow functions deal with this differently from other functions. This, indeed, was the main reason arrow functions were introduced - they are not primarily about a "nicer" syntax, even though this seems to be how many developers today use them. (And there is nothing wrong with using them that way, but you do absolutely have to be aware of how these functions behave differently.)
As the MDN link explains, the fact that arrow functions "inherit" the this of their enclosing scope is a convenience in many common situations. But, as you have discovered, it also causes problems in cases where you rely on the value of this to be a particular object. Here is a simple demonstration of how the difference arises in your case:
let username1={
email:"test#test",
login:()=>{console.log(this.email);}
};
let username2={
email:"test#test",
login:function(){console.log(this.email);}
};
username1.login(); // logs "undefined"
username2.login(); // works as expected
The reason is because in username2, with the "ordinary" function (not an arrow function) follows the normal rules for what this means inside a function. These are too difficult to go into here (although less difficult than are often thought, and I would well advise understanding what they are) - suffice to say though that the value of this inside a function depends on how the function was called, and that usually, when you call a function as a direct property of an object, as you do with username2.login() here, this will be that object (namely username2).
But with username1.login(), the function is an arrow function, which as the MDN article explains, does not follow these standard rules. Instead the this is adopted from the enclosing scope. Here that's the global scope, not a function scope, so there isn't actually a "real" this to use - and that results in the global (window) object being chosen instead. And since window.email doesn't exist, you get undefined. As proof that this is indeed the global object, recall that window.email is one and the same as a global variable called email. So if we amend the snippet to define a global variable of that name, its value is printed instead:
var email = "this is the global email var";
let username1={
email:"test#test",
login:()=>{console.log(this.email);}
};
let username2={
email:"test#test",
login:function(){console.log(this.email);}
};
username1.login(); // logs global email variable
username2.login(); // works as expected
So that's what's happening here. (Also note that, in real code, the enclosing scope will most often not be global. But it's still quite likely that the this value of the function concerned will be the global object, and even if it isn't, you'll still see undefined printed here unless that particular object happens to have an email property defined.)
The moral of the story is not to use arrow functions for object methods - because any reference to this inside them will not behave as you likely expect. In fact my personal reference is not to use arrow functions at all unless you either need their specific modification of the this rules, or if you need a "throwaway" one-line anonymous function (for example as a function argument to an array's map or filter), in which case the arrow function can make the code more readable. But increased readability and brevity is not the main reason arrow functions exist.
Arrow function is always called with the context in which it was defined. Just use a normal function.
let username={
email:"test#test",
login: function() {console.log(this.email);}
};`
Take a look at ECMAScript 2015 Spec:
Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.

What's the difference between a predefined global variable and a keyword in javascript?

For example, I see that undefined is described like a predefined global variable, while null is described like a keyword.
What's the difference?
null is not a keyword; it's a special literal value, like true. See the spec.
undefined is not a keyword either. First, it's the name of a global property with some special behaviors: it is non-configurable and non-writable (in modern browsers), meaning you cannot change its value. See the spec.
Second, it's a special value which is the value of the undefined property, the value of uninitialized variables, the return value of functions without explicit return statements, and what the void operator evaluates to.
Third, it's a type, whose only value is the undefined value.
In JavaScript, some identifiers are reserved words and cannot be used as variables or function names those called keywords e.g break, case, catch, continue, debugger, default, delete, do, else, false, finally, for, function these are some reserved keywords in javaScript.
Whereas A variable declared outside a function, becomes GLOBAL. A global variable has global scope: All scripts and functions on a web page can access it.

Binding a name for JavaScript function using variable name

I'm having an issue with the following:
I think the issue is clear, the anonymous function does not take the name of its variable .
Therefore, how do I extend Function Object Constructor to give a name to a function according to the affected variable?
You can just do this:
var i_am = function i_am() { return "I Sure Am!"; }
That syntax has always been valid, but in the past there have been some browser quirks about that. If those quirks are of concern, you can always do this:
function i_am() {
return "I Sure Am!";
}
var i_am = i_am;
That's a little bit fishy, because the binding for "i_am" in the local scope is highjacked from the function, but the function retains the internal binding of the name.
Now, there's no way to retroactively give a function an internally-bound name. Functions are pretty much frozen upon creation (and if you think about language semantics and optimization, that's the way it should be).
You can't.
The name of the function is determined as you create the function.
If you use an unnamed function expression, then the function will be created (with no name) and then assigned to the variable.
Since the variable doesn't come anywhere near the function before then, it can't be used to determine the function's name.
If you want to give a function created with a function expression a name, then use a named function expression.
var addFn = function addFn () {};
(Warning: Old versions of Internet Explorer have memory leak and scope related bugs surrounding named function expressions).

How can function references be executed properly (1)?

win points to window. NS is a temporary namespace for this post. I thought that if I wanted access to setTimeout, I could just copy over the function reference as such:
NS.setTimeout = win.setTimeout;
However, execution will throw an error:
NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object # ...
To fix this error, I just did:
NS.setTimeout = function (arg1, arg2) {
return win.setTimeout(arg1, arg2);
};
However, I don't know why this fixed it. I don't know what language mechanics are causing this behavior.
What you want is this :
NS.setTimeout = win.setTimeout.bind(win);
or what you already do, if you want to be compatible with IE8.
Because setTimeout, like many window functions, needs the receiver (this) to be window.
Another IE8 compatible solution, more elegant in my opinion than yours (because it doesn't use the fact you know the number of arguments needed by setTimeout), would be
NS.setTimeout = function(){
return win.setTimeout.apply(win, arguments);
};
The reason why you can't do that is because, when assigining, you're changeing the call context of setTimeout, which isn't allowed.
Nor is it allowed for setInterval, and many of the other native objects/functions. Again: a great rule of thumb: if you don't own the object, don't touch it. Since functions are objects in JS, that rule applies to them, too
check the specs on the global object and its properties/builtin funcitons:
There are certain built-in objects available whenever an ECMAScript program begins execution. One, the global object, is part of the lexical environment of the executing program. Others are accessible as initial properties of the global object.
And so on. But the lexical environment is quite significant. By assigning a reference to the function elsewhere, you could well be masking part of the lexical environment, or exposing too much of the global environment (eg mashups).
This fixed the problem b.c. you are changing the calling object back to the original when you call it.
return win.setTimeout(arg1, arg2);
will set the context ( or this ) back to window where it should be. The other answers are similar in the fact that they change the context to the correct value using bind to apply.

Categories

Resources