Why doesnt the outer scope get accessed in the inner scope ?
I am coming from C++ world where any reference to an unqualified variable inside a class's method is attempted to be resolved first within the object's scope and then in the outer scope. And this happens without having to use "this" keyword.
For ex:
#include <iostream>
using namespace std;
std::string name = "Global::name";
class MyClass {
private:
string name = "MyClass::name";
public:
void printName() {
// No need to use 'this' keyword to refer to the variables in the
// object's scope, unless there is an ambiguity to resolve
cout << "Name from inside printName is: " << name << "\n";
}
};
int main()
{
MyClass obj;
cout << "Name from inside main is: " << name << "\n";
obj.printName();
return 0;
}
prints
Name from inside main is: Global::name
Name from inside printName is: MyClass::name
But in javascript, the following code snippet
function fn() {
let name1 = "fnB";
console.log("Inside fn() name is : ", name1);
}
var obj = {
name1: "objA",
objFn: function() {
console.log("Inside objFn() name is : ", name1); // ERROR !!
// console.log("Inside objFn() name is : ", this.name1); // OK !
}
}
fn();
obj.objFn();
results in
Uncaught ReferenceError: name1 is not defined
at Object.objFn (my.js:10)
What is the reason javascript doesnt want to refer to the "name1" variable in the scope of "obj" object, without requiring "this" keyword to refer to it ? What is the problem that is being solved by forcing the use of "this" keyword in this context ?
Every language is different and makes different tradeoffs. An obvious difference between C++ and JavaScript wrt class/object methods:
In JavaScript, every function is a standalone object. It doesn't strongly belong to anything.
In C++, class methods belongs the class. They cannot be invoked without it.
In JavaScript, every function is a closure, i.e. it has access to free variables defined in a "higher" lexical scope.
In C++, methods are not closures.
Why does this matter? Consider the following example:
var name = 42;
var obj = {
name: "objA",
objFn: function() {
console.log("Inside objFn() name is : ", name);
}
}
Which name should objFn access according to your expectation?
As it is now, the function would log 42, because that's how lexical scoping + closures work. In order to access the object's name property I have to write this.name.
Now lets assume it was the other way round, that object properties would be accessed before the outer scope. Then in order to explicitly access the outer scope's variables, i.e. 42, we would need some new API, e.g. getVariableFromScope('name'). This is worse than always requiring this for a simple reason: It makes it more difficult to reason about the code. By always requiring this, the rules are very simply:
Want to access a property on the object? this.<property>
Want to access a variable in scope? <variable>
In your case it would be:
Want to access a variable in scope? <variable>, but only if the object doesn't have a property with the same name, otherwise getVariableFromScope('<variable>').
Want to access a property on the object? <property>, but only if there is not a local variable with the same name, otherwise this.<property>.
One possible tradeoff here is consistency vs convenience.
Also consider the following example:
var foo = 42;
function bar() {
console.log(foo);
}
Calling bar() will log 42. Now lets assume I pass the function to some third-party code someOtherFunction(foo) which does:
function someOtherFunction(func) {
var obj = createObject();
obj.func = func;
obj.func();
}
Do you see the problem? The result of calling bar now depends on whether obj has a name property or not. To resolve this, either someOtherFunction needs to know which free variables bar contains or bar needs to know that someOtherFunction assigns it to some object and has to account for that. Either way, the code would be tightly coupled.
Doing what C++ or Java does would basically mean to introduce dynamic scope, and I assume there is a reason why very few languages use it.
(Someone might argue that this is also like dynamic scope. Well, this is a single keyword. It's easier to reason about that than to reason about the space of all possible variable names that could be overwritten.)
There are probably more reason why the behavior you are describing is not desirable in JavaScript. But again, programming language design is all about tradeoffs.
The this keyword behaves quite differently in javascript from how it does in many other languages. The value of this is not figured out until the function is invoked, and may not have anything to do with the object you think its associated with.
For example, consider the following code:
const obj = {
name: 'bob',
sayName: function () {
console.log(this.name);
}
}
const verbalize = obj.sayName; // Make another way to reference the function
console.log(verbalize === obj.sayName); // They're literally the same function
// And yet they log very different things
obj.sayName(); // logs 'bob'
verbalize(); // for me, it logs 1d7dcb5e-0fde-4726-8875-4bdcd636c6eb
Why does verbalize produce such a weird result? Well, since i'm invoking the function without specifying what this should be equal to, this defaults to the global window object, and so i end up logging window.name, which for me happens to be "1d7dcb5e-0fde-4726-8875-4bdcd636c6eb".
So if the language was set up to check this before checking other scopes, the actual result would be (in some cases) to check for global variables before local variables, which is the exact opposite of what we'd like to happen. Thus, this has to be done explicitly.
(ps: while this can be set to the window object in some cases, it can also be set to undefined if you're in strict mode)
Related
I'm running this javasrcipt code on google chrome browser as an html script tag.
<script type="text/javascript">
var bar=function() {
var name='tanzeel';
console.log('inside a function');
}
console.log('My name is ' +bar.name);
</script>
I'm coming from java and cpp background. My knowledge about oop says that function in js are instantiated as an object and here variable bar is pointing to that object. So I can access all the properties of that object. Then why console.log('My name is ' +bar.name) is printing My name is bar instead of the string My name is tanzeel.
Please correct me where i am wrong and what else do i need to know. Thanks.
Your variable may be "pointing" (dat cpp lingo ;)) to an object, but you can't just treat that object any how you want. The object is a function in this case, so you cannot treat the function's body as having fields in the sense of a regular class.
The output you get is the name of the function.
To have this work, you must instantiate the object using new keyword. You also have to assign properties to the class in order to access them.
var bar=function() {
this.name='tanzeel';
//console.log('inside a function');
}
var b = new bar()
console.log(b.name);
There are two separate issues here.
First, functions are objects and can have properties. Variables defined in the scope of a function are completely different to properties of the function object. They exist only while the function is running (although c.f. closures) and are referred to directly and not in relation to the function.
Second, functions can have names. Typically this comes from an explicit name in the function expression:
var bar = function foo () { };
… but since a change in JS a few years ago, anonymous function expressions get a name from the variable that they are assigned to.
var bar = function () { };
The fact that you have a variable named name inside the function is unrelated to the function having a property called name.
When you assign string tanzeel to variable name, you don't change name property of the bar function. Instead you just create name variable in the lexical environment of bar function.
bar.name in console.log statement evaluates to bar because the function infers it from it's syntactic position
The expected behaviour is understandable. This is because functions are treated as objects in javascript. Each object has a set of properties. Similarly, functions have a property name in their prototype chain which evaluates to the name of the function. Read more here:
https://developer.mozilla.org/enUS/docs/Web/JavaScript/Reference/Global_Objects/Function/name
Also, check out the console in the image below. You can see a name property there inside the constructor.
I've done a lot of searching and some playing around, and I'm pretty sure the answer to this question is no, but I'm hoping a JavaScript expert might have a trick up his sleeve that can do this.
A JavaScript function can be referenced by multiple properties, even on completely different objects, so there's no such thing as the object or property that holds the function. But any time you actually call a function, you must have done so via a single object (at the very least, the window object for global function calls) and property on that object.
(A function can also be called via a function-local variable, but we can consider the function-local variable to be a property of the activation object of the scope, so that case is not an exception to this rule.)
My question is, is there a way to get that property name that was used to call the function, from inside the function body? I don't want to pass in the property name as an argument, or closure around a variable in an enclosing scope, or store the name as a separate property on the object that holds the function reference and have the function access that name property on the this object.
Here's an example of what I want to do:
var callName1 = function() { var callName = /* some magic */; alert(callName); };
var obj1 = {'callName2':callName1, 'callName3':callName1 };
var obj2 = {'callName4':callName1, 'callName5':callName1 };
callName1(); // should alert 'callName1'
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'
From my searching, it looks like the closest you can get to the above is arguments.callee.name, but that won't work, because that only returns the name that was fixed to the function object when it was defined, and only if it was defined as a named function (which the function in my example is not).
I also considered that maybe you could iterate over all properties of the this object and test for equality with arguments.callee to find the property whose value is a reference to the function itself, but that won't work either (in the general case), because there could be multiple references to the function in the object's own (or inherited) property set, as in my example. (Also, that seems like it would be kind of an inefficient solution.)
Can this be done?
Short answer:
No, you cannot get "the property name" used to call your function.
There may be no name at all, or multiple names across different scopes, so "the property name" is pretty ill defined.
arguments.callee is deprecated and should not be used.
There exists no solution that does not use arguments or closure.
Long answer:
As thefourtheye commented, you should rethink what you are trying to do and ask that instead in a new question. But there are some common misconceptions, so I will try to explain why you cannot get the "simple property name".
The reason is because it is not simple.
Before we go ahead, let us clarify something. Activation Objects are not objects at all.
The ECMAScript 5.1 specification calls them Environment Records (10.2.1), but a more common term is Scope chain.
In a browser the global scope is (often) the window object, but all other scopes are not objects.
There may be an object that you use to call a function, and when you call a function you must be in some scope.
With few exceptions, scopes are not objects, and objects are not scopes.
Then, there are many names.
When you call a function, you need to reference it, such as through an object property. This reference may have a name.
Scope chain has declarations, which always have a name.
A Function (the real function, not reference) may also have a function name - your arguments.callee.name - which is fixed at declaration.
Not only are they different names, they are not (always) the "the property name" you are seeking.
var obj = { prop : function f(){} }, func = obj.prop;
// "obj" and "func" are declarations.
// Function name is "f" - use this name instead of arguments.callee
// Property name is "prop"
func(); // Reference name is "func"
obj.prop(); // Reference names are "obj" and "prop"
// But they are the same function!
// P.S. "this" in f is undefined (strict mode) or window (non-strict)
So, a function reference may comes from a binding (e.g. function declaration), an Object (arguments.callee), or a variable.
They are all References (8.7). And reference does have a name (so to speak).
The catch is, a function reference does not always come from an object or the scope chain, and its name is not always defined.
For example a common closure technique:
(function(i){ /* what is my name? */ })(i)
Even if the reference does have a name, a function call (11.2.3) does not pass the reference or its name to the function in any way.
Which keeps the JavaScript engine sane. Consider this example:
eval("(new Function('return function a(){}'))()")() // Calls function 'a'.
The final function call refers the eval function, which refers the result of a new global scope (in strict mode, anyway), which refers a function call statement, which refers a group, which refers an anonymous Function object, and which contains code that expresses and returns a function called 'a'.
If you want to get the "property name" from within a, which one should it get? "eval"? "Function"? "anonymous"? "a"? All of them?
Before you answer, consider complications such as function access across iframes, which has different globals as well as cross origin restriction, or interaction with native functions (Function.prototype.bind for example), and you will see how it quickly becomes hell.
This is also why arguments.caller, __caller__, and other similar techniques are now all deprecated.
The "property name" of a function is even more ill defined than the caller, almost unrealistic.
At least caller is always an execution context (not necessary a function).
So, not knowing what your real problem is, the best bet of getting the "property name" is using closure.
there is no reflection, but you can use function behavior to make adding your own fairly painless, and without resorting to try/catch, arguments.callee, Function.caller, or other strongly frowned-upon behavior, just wasteful looping:
// returning a function from inside a function always creates a new, unique function we can self-identify later:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//the one ugly about this is the extra "()" at the end:
var obj1 = {'callName2':callName(), 'callName3':callName() };
var obj2 = {'callName4':callName(), 'callName5':callName() };
//test out the tattle-tale function:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
if you REALLY want to make it look like an assignment and avoid the execution parens each time in the object literal, you can do this hacky routine to create an invoking alias:
function callName() {
return function callMe(){
for(var it in this) if(this[it]===callMe) return alert(it);
}
};
//make an alias to execute a function each time it's used :
Object.defineProperty(window, 'callNamer', {get: function(){ return callName() }});
//use the alias to assign a tattle-tale function (look ma, no parens!):
var obj1 = {'callName2': callNamer, 'callName3': callNamer };
var obj2 = {'callName4': callNamer, 'callName5': callNamer };
//try it out:
obj1.callName2(); // alerts 'callName2'
obj2.callName5(); // alerts 'callName5'
all that aside, you can probably accomplish what you need to do without all the looping required by this approach.
Advantages:
works on globals or object properties
requires no repetitive key/name passing
uses no proprietary or deprecated features
does not use arguments or closure
surrounding code executes faster (optimized) than
a try/catch version
is not confused by repeated uses
can handle new and deleted (renamed) properties
Caveats:
doesn't work on private vars, which have no property name
partially loops owner object each access
slower computation than a memorized property or code-time repetition
won't survive call/bind/apply
wont survive a setTimeout without bind() or a wrapper function
cannot easily be cloned
honestly, i think all the ways of accomplishing this task are "less than ideal", to be polite, and i would recommend you just bite the coding bullet and pass extra key names, or automate that by using a method to add properties to a blank object instead of coding it all in an object literal.
Yes.
Sort Of.
It depends on the browser. (Chrome=OK, Firefox=Nope)
You can use a factory to create the function, and a call stack parsing hack that will probably get me arrested.
This solution works in my version of Chrome on Windows 7, but the approach could be adapted to other browsers (if they support stack and show the property name in the call stack like Chrome does). I would not recommend doing this in production code as it is a pretty brittle hack; instead improve the architecture of your program so that you do not need to rely on knowing the name of the calling property. You didn't post details about your problem domain so this is just a fun little thought experiment; to wit:
JSFiddle demo: http://jsfiddle.net/tv9m36fr/
Runnable snippet: (scroll down and click Run code snippet)
function getCallerName(ex) {
// parse the call stack to find name of caller; assumes called from object property
// todo: replace with regex (left as exercise for the reader)
// this works in chrome on win7. other browsers may format differently(?) but not tested.
// easy enough to extend this concept to be browser-specific if rules are known.
// this is only for educational purposes; I would not do this in production code.
var stack = ex.stack.toString();
var idx = stack.indexOf('\n');
var lines = ex.stack.substring(idx + 1);
var objectSentinel = 'Object.';
idx = lines.indexOf(objectSentinel);
var line = lines.substring(idx + objectSentinel.length);
idx = line.indexOf(' ');
var callerName = line.substring(0, idx);
return callerName;
}
var Factory = {
getFunction: function () {
return function () {
var callName = "";
try {
throw up; // you don't *have* to throw to get stack trace, but it's more fun!
} catch (ex) {
callName = getCallerName(ex);
}
alert(callName);
};
}
}
var obj1 = {
'callName2': Factory.getFunction(),
'callName3': Factory.getFunction()
};
var obj2 = {
'callName4': Factory.getFunction(),
'callName5': Factory.getFunction()
};
obj1.callName2(); // should alert 'callName2'
obj1.callName3(); // should alert 'callName3'
obj2.callName4(); // should alert 'callName4'
obj2.callName5(); // should alert 'callName5'
I'm trying to write an application in JavaScript, which I've been using for bits of scripting in web pages for years, and I find my understanding of scope and object orientation is coming up somewhat short. My background is mostly in object oriented languages like C# and Ruby so JavaScript's weird pseudo object-oriented functional approach is confusing me no end.
What I'm having trouble with is this and why I seem to always need it in every reference to anything in my class. It just seems to result in an inordinate amount of typing in order to write much that is useful in JS and I can't help but feel I must be doing it wrong somehow:
function MyClass()
{
var a=1;
this.b = 2;
this.internalMethod= function()
{
console.log("a is: "+a); // returns "a is: 1"
// console.log("b is: "+b); - this fails because b is undefined
console.log("this.a is: "+this.a); // returns "this.a is: undefined" but doesn't crash.
console.log("this.b is: "+this.b); // returns "this.b is: 2"
}
}
MyClass.prototype.externalMethod = function()
{
// console.log("a is: "+a); - fails
// console.log("b is: "+b); - fails
console.log("this.a is: "+this.a); // "this.a is: undefined"
console.log("this.b is: "+this.b); // "this.b is: 2"
}
var m = new MyClass();
m.internalMethod();
m.externalMethod();
What I am understanding from this is that if I am adding a new public method through the class.prototype approach, I only have access to properties that are defined with this.
If I create an internal method in the class definition function I have access to any var values in the class itself and I can access this.property as long as I include the this.
Is this correct? Do I always have to include an explicit object reference to access properties in any functions that use the prototype method? If so, should I be declaring all my functions within the parent class function rather than using the class.prototype pattern for adding them?
In essence I am looking for a standard approach to managing variable scope when writing object oriented Javascript. Most of the articles I can find on this topic are either basic introductions to object orientation or seem to gloss over this area. A lot of my classes are fairly data intensive and having to make calls in the form this.myMethod( this.firstArray, this.secondArray, this.thirdArray, this.fourthArray ) seems like a long cut and impedes the readability of code.
(I am aware of the var that=this trick for avoiding caller scope problems but I didn't want to mess up my examples with it as as far as I know it's not really pertinent to my question.)
function MyClass()
{
var a=1;
this.b = 2;
this.internalMethod= function()
{
console.log("a is: "+a); // returns "a is: 1"
// console.log("b is: "+b); - this fails because b is undefined
console.log("this.a is: "+this.a); // returns "this.a is: undefined" but doesn't crash.
console.log("this.b is: "+this.b); // returns "this.b is: 2"
}
}
In that code, the first console.log will return the right value, because you declared the variable a and then declared the function, which grabs it's environment and saves it all into something called closure (this explanation might be a bit off), so what happens here, is that when you call internalMethod, that function in it's environment also has the definition of a. Which might be confusing, because when you do your second console.log your see "undefined", which is because the a variable is not an attribute of this, but rather just a global variable to the scope of your internalMethod.
MyClass.prototype.externalMethod = function()
{
// console.log("a is: "+a); - fails
// console.log("b is: "+b); - fails
console.log("this.a is: "+this.a); // "this.a is: undefined"
console.log("this.b is: "+this.b); // "this.b is: 2"
}
In that code, a is not defined, becuase it didn't exist when you declared your method, but this.b does, because is part of the attributes of MyClass, which is what you're working on.
So, to summarize, you'll want to use the this keyword when adding or using internal attributes to your "class" (which you should not call class, since that doesn't exists here). It might be a pain, but it's the only way to reference internal attributes of your objects from within it's methods.
Additionally, you might find these two articles interesting to read, since they explain a bit about OOP techniques for JS and some common mistakes:
http://www.commented-out.com/2012/06/12/javascript-oop-for-the-uninitiaded/
http://www.commented-out.com/2012/05/28/javascript-youre-doing-it-wrong/
Let me know if you have more questions.
What I am understanding from this is that if I am adding a new public method through the class.prototype approach, I only have access to properties that are defined with this.
If I create an internal method in the class definition function I have access to any var values in the class itself and I can access this.property as long as I include the this.
There are no such things as "internal" and "external" properties, only "own" and "inherited" properties. In your example, internalMethod is directly assigned to the new object, while externalMethod is inherited from the prototype. They are not different or special in any way. Any two functions that are defined in different scopes are always different.
internalMethod has access to the local variables in the constructor because it is a closure.
Do I always have to include an explicit object reference to access properties in any functions that use the prototype method?
It's important to understand that there is no implicit connection between functions and the objects "they are assigned" to. Functions are independent entities.
The connection is only determined at runtime, by setting this accordingly. So yes, you will need this, for every function, not only those assigned to the prototype. Learn more about this.
If so, should I be declaring all my functions within the parent class function rather than using the class.prototype pattern for adding them?
This is extensively discussed here:
Declaring javascript object method in constructor function vs. in prototype
Use of 'prototype' vs. 'this' in JavaScript?
In essence I am looking for a standard approach to managing variable scope when writing object oriented Javascript.
My subjective advice:
Keep it simple. Don't try to simulate private variables/methods through local variables and closures. Initialize and assign instance-specific data in the constructor, and assign anything that should be shared between instances (such as methods) to the prototype. Use a naming convention, such as this.privateProperty_ to indicate properties that should be accessed by external code.
A lot of my classes are fairly data intensive and having to make calls in the form this.myMethod( this.firstArray, this.secondArray, this.thirdArray, this.fourthArray ) seems like a long cut and impedes the readability of code.
In this example, this inside myMethod will refer to the object itself, so you can access this.firstArray, this.secondArray, etc, just in like that inside the function. You don
t have to pass them.
JavaScript doesn't look up variables in an object, because it's not a classical inheritance language. It's more based on Scheme, with its lexical scope.
Your examples show 2 things:
this refers to the object being instantiated
a is just a variable
In the internalMethod, you're still in the constructor function. So you have access to the variables defined in the constructor (function scope and lexical scope). However, once you get out of the constructor, a is not reachable anymore.
this.b means that on the instantiated object, you attach the property b. It's basically the equivalent of this:
function Foo() {}
var foo = {
b: ''
};
foo.constructor.prototype = Foo.prototype;
Basically. Instantiating with new does a little bit more.
So if you want to access the instantiated object, you have to use this. If you just want to use the power of lexical scope, you can also play with simple variables and closures.
For example, this constructor will instantiate a new object every time it's called, and there is no this:
function Foo() {
var a = 1;
var b = 2;
return {
internalMethod: function() {
return a;
},
incB: function() {
return ++b;
}
};
}
var foo = Foo();
foo.internalMethod(); // 1
foo.incB(); // 3
foo.incB(); // 4
var bar = new Foo();
bar.incB(); // 3
This pattern is called the "module pattern".
If you find limiting the use of an object, you can return an object by using a immediately-executed function (and thus having another scope to play with):
function Foo() {
var a = 1;
var b = 2;
return function() {
var c = 3;
return {
a: a,
c: c
};
}();
}
I seem to always need it in every reference to anything in my class. It just seems to result in an inordinate amount of typing in order to write much that is useful in JS
You're not doing it wrong. In my comment I referenced this answer where I try to explain every stage of writing a constructor, after reading it you'll understand why it's not wrong to use this, however, JavaScript does provide another statement, with that you could use to reduce how much you need to type after a property is initialised.
function MyConstructor() {
this.a = 1; // initialise properties with `this`
this.b = 2;
this.c = 3;
this.d = 4;
}
MyConstructor.prototype = {};
MyConstructor.prototype.foobar = function() {
var c = 5, e = null;
with (this) { // `with` now means you can do `a` instead of `this.a`
var d = 6;
console.log(a, b, c, d, e);
a = 0 - a; // in `this`, property gets set to property
b = -2; // in `this`
c = -c; // in `this`, var'd outside `with`, property gets set to property
d = -d; // in `this`, var'd inside `with`, property gets set to var
e = 100; // not in `this`, var'd, var gets set (not var'd => global set)
}
};
x = new MyConstructor(); // new instance
console.log(x.a, x.b, x.c, x.d, x.e);
// 1 2 3 4 undefined -- undefined as no property `e`
x.foobar();
// 1 2 3 6 null -- 6 from var, null from `var e = null`
console.log(x.a, x.b, x.c, x.d, x.e);
// -1 -2 -3 -6 undefined -- undefined as still no property `e`
I suggest reading about the Javascript module pattern to learn about public / local attributes and scope.
var declares a variable that will be accessible in the current function and the inner ones.
Any method / attribute attached to an object is said "public" as it can be accessed from anywhere.
Local variables, 'trapped' in closures, are used to emulate private members.
Attaching public methods to the prototype is the best memory-efficient approach to reuse those methods on different instances. You could use closures as well in those prototype methods.
One thing to note: as closures emulate 'private' variables but not 'protected' ones, it makes inheritance quite tricky when you need it.
var a = {
text : 3,
logText : function () {
console.log(this.text);
},
callLogText : function() {
logText();
}
};
a.callLogText();
This will genernate a ReferenceError: logText is not defined error message.
Instead, you prefix this to the logText() method, it will be ok. No error msg will pop.
var a = {
text : 3,
logText : function () {
console.log(this.text);
},
callLogText : function() {
this.logText();
}
};
I really cant figure out the reason.
You need to learn the JavaScript scoping rules. This blog post gives a good introduction.
In a nutshell, JavaScript follows some rules when you use a variable name (for the purpose of this explanations, function definitions are pretty much like variable declarations).
What probably confuses you is this:
var a = { b: ...};
var a = function() { var b = ... }
In both cases, you get a new variable a. In the first case, it's an object with a property b. In the second case, it's a function which has a nested scope in which a new variable b is defined.
JavaScript will look in the current and all parent scopes for variables. But object definitions are no scopes. As far as JavaScript is concerned, the property b is invisible unless you make it visible by using the special variable this which always references the "current" object (in your example, that is a).
Since the properties of the object a are not "in scope", JavaScript can't find logText() unless you tell it to look in this. If you don't say anything, JavaScript will look in the current scope (the body of the function callLogText), then the parent scope (in which a is defined) and then in any parent scopes of that.
It's not a quirk. It's how most languages function when it comes to objects.
logText() is a method of the a object, not a function.
You need to call methods internally as this.methodName() or externally as object.methodName().
logText(); is to execute a global function logText which is undefined.
this.logText(); is to execute the function a.logText.
Calling
logText();
means somewhere there is a function named logText(), but here you have defined logText() as a property of an object, so to access the logText() you have to refer it with the help of the object it is defined in. In this case it is in the same object so you refer to the same object by saying this.
Before actually asking anything, I'll go ahead and say this is a theoretical question; however, it might be implemented on a website later on.
Anyway, I have a variable, any variable. Let's say it's a and its scope is global. Now, for a specific function, I want to set that variable's value to something other than it's global value, but based on it, and without changing its value globally. For example:
a = {something: "Safe", other: "Foo"}
function hello(){
var a = a.other; // Foo
a.something; // Undefined
}
a.something; // Safe
a.other; // Foo
The issue with the above code is that when I define var a in the function, it will have already cleared the value of the global a locally before setting it; in other words, it would return something like Can't access property [other] of undefined [a].
Again, a should still be a (so using another variable name is not an option, or at least not the ideal one). In fact, the global a should not be accessible from the function hello.
Edit: window will also be overwritten with null, regarding Milan Jaric's answer.
Thanks in advance!
Every global can be accessed using window object, with a little changing your code here is example
a = {something: "Safe", other: "Foo"}
function hello(){
var a = window.a.other; // Foo
console.log(window.a.something); // Safe
}
a.something; // Safe
a.other; // Foo
hello();
or
a = {something: "Safe", other: "Foo"}
function hello(){
var a = this.a.other; // Foo
delete a;
console.log(this.a.something); // Safe
}
a.something; // Safe
a.other; // Foo
hello();
This is what I was looking for...now, before you think I had the answer before I asked, I didn't, I was only able to reach a tangible solution based on Milan Jaric's answer (thanks btw).
a = {something: "Safe", other: "Foo"}
function hello(b){
var window = null;
var a = b; // a.other;
a.something; // Undefined
}
a.something // Safe
a.other // Foo
hello(a.other)
(I never really said what could or couldn't go outside the function).
Let's say it's a and its scope is global.
You mean "a is a global variable".
... for a specific function, I want to set that variable's value to
something other than it's global value, but based on it, and without
changing its value globally.
Impossible. You can create a variable with the same name that is on a scope chain, however you can't conditionally create properties of variable objects (i.e. the objects used for identifier resolution on the scope chain). You can only declare local varaibles, which means they exist before any code is run and so can't be conditional, or you can assign directly to an undeclared identifier at which point it becomes a global variable.
[snipped code]
The issue with the above code is that when I define var a in the
function, it will have already cleared the value of the global a
locally before setting it;
The code doesn't in any way "clear" the value of a. It creates a local variable a so that the identifier a will resolve to that variable, not to the global a. To differentiate betweent the two, you can access the global a as a property of the global object:
var a = 'whatever';
var myFunction = (function(global) {
return function() {
var a; // local a
global.a; // global a
}
}(this));
Again, a should still be a (so using another variable name is not an
option, or at least not the ideal one). In fact, the global a should
not be accessible from the function hello.
Impossible, though it might be almost possible in ES5 strict mode provided the code attempting to access the global a is inside another function and can't get a reference to the global object.
But I don't think you can guarantee that.