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.
Related
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)
I'm following a js tutorial,then I noticed this way to create a class/objects
//create a Book like class function (construct),
//pretty normal unti I've learnt, except for the return part
var Book = function(name){
this.name = function(){
return name;
}
}
//then using the new operator, create and object of Book sending the "name" in the constructor
var myBook = new Book("Javscript book");
//and then I can get it back with the method name
//(which actually doesn't need to be named as "name")
console.log(myBook.name());
My concern is why/how it works, I mean How I'm able to get the property "name"? and if it's even a property in the myBook object, because there's no an explicit assignment or prop declaration, until I know it works or it's set when the constructor received the parameter in the "name" argument, but not sure and I'm probably need to know how js code is executed to understand how this works.
My theory, is that actually I'm returning the parameter I sent in the constructor, not a property from the object, the argument is still "alive" in the myBook instance then it can be used in the return statement, am I right ?
Welcome to the world of Closures!
Let me try to give you a brief introduction to it.
First off, let me give the formal definition: a closure is a link(present in the function object) from a function object to the scope in which it was defined.
Ok, that does not make much sense right now.
We need to know:
What is scope?
What is a function object?
What does the statement mean?
What is scope?
Scope of a variable refers to the places where a variable is accessible. Javascript has function scope, which means variables declared(with the var keyword) inside a function are visible only inside the function. Each function invocation has it's own scope object. So if you call myFunction(), and call it a second time myFunction(), the two function calls have separate scope objects. So, if you call a function, you are in effect creating a scope object for that function invocation.
What is a function object?
When you declare a function
function Functions_are_objects()
{
//your code
}
A function object is created and filled with your code, and a reference to that function object is stored in the variable Functions_are_objects. This way when you call Functions_are_objects(), Javascript knows which function you want to execute.
Now, let's understand how your code works:
When you write
var Book = function(name){
this.name = function(){
return name;
}
}
and when you call it
var myBook = new Book("Javscript book");
the following happens:
1.) A (anonymous) function object is created and Book stores it's reference.
2.) When a statement is encountered with the new operator it works in this way
i. A new empty object is created.
ii. If the (constructor) function Book has a prototype property, the internal prototype property of the newly created object is set to it.
iii. The execution context is set to this newly created object and the function Book is called. When we say "Set the execution context to this newly created object", we mean that the this refers to the newly created object inside the function Book. Now the function Book is executed, and the statement this.name is encountered. Since this is the newly created object, and since it has no name property, a new property "name" is implicitly created and assigned the function object. At this point, based on the formal definition of Closures that we saw earlier, the function object has a reference to the scope in which it was created. Recall that, Javascript has function scope, and at the point of running
this.name = function(){
return name;
}
The scope is the scope of the function invocation of the function Book.
When you called
var myBook = new Book("Javscript book");
to the function Book, the name parameter is a local variable to this function invocation, and by the above call, the local variable "name" gets the value "Javscript book". Make sense, so far?
Now, since the function object
function(){
return name;
}
was created in this invocation of the Book function, the above function object has the reference to this local variable name.
Now, putting it all together, when you do:
console.log(myBook.name());
myBook.name function is called, and since this function had a reference to the scope in which Book was called, and that scope has the value for the variable name, and it returns this value.
You are correct that the "name" value that you are seeing is not actually a property of the instance you are creating, but rather the parameter you are passing into the constructor of the object. The way this specific example works is that when you call the constructor, the name parameter that you passed in exists within the scope of that instance and is outputted by the name() method that is defined.
Yes, you are correct that the method is returning the value of the parameter.
The argument is not kept in the instance of the object. The parameter is a local variable in the scope where the inner function is created, so it's caught in the closure for that function. That's why the name method can still access the parameter after the function that creates the object has finished (and the scope is gone).
In javascript, this is call Closure.
A closure is a function that “captures” values near where it was born.
Basically Javascript automatically creates a local copy of the variable that is passed.
Please refer to this link for more information: How do JavaScript closures work?
I'm having trouble with a JS prototype object I'm working on. What I'm trying to do is define a class-level variable as an object literal, then refer back to one of the class's prototype methods to set a property of the class-level variable, but I'm not getting anywhere. Here's what I am trying to do, in a simplified example:
var foo = function(args)
{
this.name = 'bar';
}
foo.stuff = { barbaz: this.foobarbaz(2) };
foo.prototype.foobarbaz(int)
{
return int;
}
alert(foo.stuff.barbaz); // should alert 2, but I'm missing something
I'm wondering if I'm just misunderstanding the scope of 'this' in this instance, or if this.foobarbaz() is undefined when I assign it to foo.stuff.barbaz.
Is it possible to refer to an object's prototype methods from within a class-level variable like this?
Here is what you need to know:
You should define your method on the prototype like foo.prototype.foobarbaz = function(int) {...}. Your current syntax is not valid.
You're trying to use the method before you define it. If you're expecting function hoisting to work here, that only applies to function declarations, not assignments. Move the assignment of foobarbaz above the first time you use it.
In this function you've provided, this is not foo. Each function has its own value of this (called the function's "context"), set each time the function is invoked. You can see the rules for how a function's context is set in several answers to Understanding Javascript scope with "var that = this".
Instead, here, you'll need to use foo.foobarbaz(2) instead of this.foobarbaz(2), because this is probably window (assuming you call this code not as the method of an object and not in JavaScript's strict mode).
My question is dead simple.
I just casually discovered that once you have defined a property with this. into an object, you don't need to prepend this. anymore when you want to call them.
So this. is really meant to be used ad definition time, like var?
I found it my self shortly after, i was referencing the window object with this. since i called my object without using new, so like it was a function.
One extra question, maybe for comments. Inside the main object, if i create a new object, and use this during the object definition, this this what will be referring to?
No, unless the context of this is a global object, such as window. Take the following example:
function Foo(bar) {
this.data = bar;
console.log(this.data); // OK
console.log(data); // ReferenceError
}
In this example, you'll get a ReferenceError: data is not defined on the first console.log(data), unless, data is a global variable. To access the instance's public member, you have to use this.data.
References:
Understanding JavaScript’s this keyword
The this keyword
There are all sorts of circumstances where you MUST use this in order to reference the right data.
These two implementations do very different things:
Array.prototype.truncate(newLen) {
// sets the length property on the current Array object
this.length = newLen;
}
Array.prototype.truncate(newLen) {
// sets a global variable named length
length = newLen;
}
var arr = [1,2,3,4,5,6,7];
arr.truncate(2);
You MUST use this in order to control what happens if you want to modify the current object. Your assumption that you can leave it off and it will still modify the current object's properties is not correct. If you leave it off, you are modifying global variables, not member properties.
So this. is really meant to be used ad definition time, like var?
No, the point of this is to be the current scope of execution. You can (and will) run into weird errors if you don't use this. For example, imagine you are an object with a property val and then on the prototype of that object you have
App.obj = function(){
this.val = 'initial';
}
obj.prototype.myMethod = function(val) {
// how would you assign argument val to object val?
}
also note that your reasoning breaks down with methods.
obj.prototype.meth2 = function(){
myMethod(); // fails where this.myMethod() would work.
}
See http://jsfiddle.net/BRsqH/:
function f(){
this.public='hello!';
var hidden='TOP SECRET!';
}
var instance=new f();
alert('Public data: '+instance.public+ /* gives "hello!" */
'\nHidden data: '+instance.hidden /* gives undefined */
);
Variables created with var are hidden and cannot be viewed nor modified outside the function which created them.
But variables created with this are public, so you can access them outside the function.
I think I got it.
I defined my object as function My_Object(){...} and then called it with MyObject(). This way the My_Object was treated as a function, not an object and therefore this == window.
So in the end I was attaching properties and methods to window instead of My_Object! That's way there were available without prepending .this.
The right way to initialize My_Object as an object is to call it like this new My_Object, isn't right?
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.