Given the following Javascript example:
var obj = function() {
var _c = function() {
console.log("c")
}
return {
a: function() {
b();
},
b: function() {
console.log("b");
},
c: function() {
_c();
}
}
}();
calling obj.a() gives an error that b is not defined. This error can be solved by changing b() to this.b(). Can anyone help explain why this is necessary while c can access _c?
_c is a local variable that is in scope when _c() is executed. b is not; it is only found on the object itself, so it can be found by this.b.
This confusion is indicative of transplanting object-oriented concepts from other languages to JavaScript. There are no private and public members in JS, and you can't call methods on the same object by leaving the object prefix. There's just local variables (v when var v or let v), global variables (v when no var v or let v) and object properties (obj.prop). A method is object property that contains a function; no more, no less.
Need to use this.b because you are returning an object and 'b' in this context is the property of that object. you need to explicitly stated that using this
While _c is a local function defined inside the closure, you can access access it directly in the return object and does not refer to the return object.
You should not call b() directly.
var obj = function() {
var _c = function() {
console.log("c")
}
return {
b: function() {
console.log("b");
},
a: function() {
this.b();
},
c: function() {
_c();
}
}
}();
obj.a();
Explanation added :
You are calling b() inside a function where b() is defined on the object. So to call the function b() inside any other function, you should call b with reference to the object like
this.b();
Related
When I use var keyword to declare any variable it gets declared inside the enclosing scope. However in the code below, I have declared function c (inside an object method a.b) with var keyword and still this inside the function c is bound to the global object window. Why is this?
var a = {
b: function () {
var c = function () {
return this;
};
return c();
}
};
document.write(a.b()); //prints: [object Window]
The value of this is determined by context, not scope.
When you call a function without any context (context.func()) as you do there (c()), the default context is the default object (which is window in browsers) unless you are in strict mode (in which case it is undefined instead).
(There are exceptions to this rule, such as apply, call, bind, and new but none of them apply here).
Many people get confused by this. The value this depends on one of 4 methods of invocation.
However, functional invocation and method-invocation cause most of the confusion.
If a function is a member of an object, this is the object itself.
obj.someFunction(); //method invocation
If a function is called without context this is the global object (in 'strict mode' this is undefined.)
someFunction(); //functional invocation
The confusion occurs when a function is called within an object, but not as a member of the object as in anObject.testWithHelper(..);
var testForThis = function(isThis, message) {
//this can be confusing
if(this === isThis)
console.log("this is " + message);
else
console.log("this is NOT " + message);
};
//functional invocation
testForThis(this, "global"); //this is global
var anObject = {
test: testForThis, //I am a method
testWithHelper: function(isThis, message) {
//functional invocation
testForThis(isThis, message + " from helper");
}
};
//method invocation
anObject.test(anObject, "anObject"); //this is anObject
//method invocation followed by functional invocation
anObject.testWithHelper(anObject, "an object"); //this is NOT anObject from helper
Here is my JSFIDDLE
If you would like c to return a, you can use closure:
var a = {
b: function () {
var that = this;
var c = function () {
return that;
};
return c();
}
};
Or avoid this all together:
var getNewA = function() {
var newA = {};
newA.b = function() {
var c = function() {
return newA;
};
return c();
};
return newA;
};
var newA = getNewA();
I know you can have one javascript instantiated object inherit the prototype of another constructor with constructer.prototype.__proto__ = otherConstructer.prototype, but can you use the call method like this to do the same thing?:
function constructor () {
otherConstructor.call(this);
}
No, the prototype can't be replaced except by referencing the object itself and directly replacing it with the __proto__ property, which doesn't exist in all implementations. Look at this sample code:
function B() {
this.someValue = "BBB";
}
B.prototype.testfunc = function() {
console.log("Called from B: someValue =" + this.someValue);
}
function A() {
this.someValue = "AAA";
return B.call(this);
}
A.prototype.testfunc = function() {
console.log("Called from A: someValue =" + this.someValue);
}
var test = new A();
test.testfunc();
// Will output "Called from A: someValue =BBB"
As you can see, the B constructor is correctly called and the object setup is from B and not A, but nevertheless the object's prototype is still from A. You can, of course, replace individual functions:
test.testfunc = B.prototype.testfunc;
test.testfunc();
// Will output "Called from A: someValue =BBB"
If you want a great explanation of why this is so, check out the accepted answer to this question.
Edit: There is no association with B.prototype when an A object is created. If you changed the code so that A.prototype.testfunc is not defined, then even though the A constructor calls B, nevertheless calling test.testfunc() will result in an undefined exception.
A = {
f1: function() {
return {
a: function(){ alert('sss'); }
}
}
}
A.f1().a();
Why is it used in this way?
Why is the method a() bound to A.f1()?
Member function f1 of A returns an object literal with its member a set to a function. It could've also been written as:
A = {
f1: {
a: function() { alert('sss'); }
}
}
A.f1.a();
Returning an object could in this case be personal preference. There is no functional difference between these two examples.
When you do as below:
var x = A.f1();
What you get on to x is the object returned by the f1 function. which is:
{
a: function(){ alert('sss'); }
}
now the object 'x' has function a() on it. You can call that function as:
x.a();
Which is exatly similar to:
A.f1().a();
I have an object litrel that has 2 anonymous functions defined as such:
obj = {
funcA : function(){
var a = 'a';
},
funcB : function(){
// but how do you access the scope in 'funcA' to access variable 'a'?
console.log(a)
}
}
I do not want to pass any variables just the scope of 'funcA' - thoughts?
JavaScript scope doesn't work like that because it has (only) function scope (except when using the let keyword).
What you could do is...
obj = {
a: 0,
funcA: function() {
this.a = 'a';
},
funcB: function() {
console.log(this.a);
}
};
jsFiddle.
You can use the a closure with the module pattern to get access to variables in an outer scope. More than one function can accesses the variable:
var obj = (function() {
var a;
return {
setA: function(value) {
a = value;
return a;
},
getA: function(value) {
return a;
},
multiplyA: function(value) {
a = a * value;
return a;
}
};
}());
alert( obj.setA(5) ); // 5
alert( obj.multiplyA(2) ); // 10
alert( obj.getA() ); // 10
See Douglas Crockford's article on Private Members in JavaScript. In this way, functions can share a common variable object on their scope chain. You still can't reference it or pass it to another function, but you might be able to get the functionality you want.
Does this code do what you want? If not, I'm really curious as to why.
obj = {
funcA : function(){
this.a = 'a';
alert(this.a);
},
funcB : function(){
// but how do you access the scope in 'funcA' to access variable 'a'?
alert(this.a);
}
}
obj.funcA();
obj.funcB();
What is the difference between accessing the actual scope of a separate function and setting members on the parent object as I have done?
Also, since there isn't a way of passing scope, are you just going to use something similar to this code instead?
I am having a JavaScript namespace say
A={
CA: function() {
this.B();
},
B: function() {
var test='test';
var result='t1';
C: function() {
this.test='test1';
.....
.....
return 'test1';
}
result=this.C();
return result;
}
}
Now when I am executing such code it is giving that TypeError: this.C is not a function. Can somebody tell me why it is so. I know it is something related with lexical scoping but am unable to understand this.
You have to be careful when you use this to identify anything in Javascript because each time you change scope "this" changes.
Assigning the 'this' reference to it's own variable helps get around this.
var a = new function() {
var self = this;
self.method = function() { alert('hiya'); };
var b = function() {
this.method(); // this isn't 'a' anymore?
self.method(); // but 'self' is still referring to 'a'
};
};
I think the problem is that when this.C() is executed inside the function referred to by B, this refers to the object that contains B, that is, object A. (This assumes B() is called within the context of A)
The problem is, C does not exist on the object A, since it's defined within B. If you want to call a local function C() within B, just use C().
EDIT:
Also, I'm not sure what you've posted is valid JavaScript. Specifically, B should be defined this way, since you can't use the object:property syntax within a function.
B: function()
{
var test='test';
var result='t1';
var C = function()
{
this.test='test1';
return 'test1';
}
result=C();
return result;
}
I am actually surprised that your code doesn't give you error on the 'C:' line.
Anyway, your syntax to define a function is not correct. Define it using the var keyword. Also, notice that I created the 'closure' so that the function C can access 'this'. See the code below:
A={
CA: function()
{
this.B();
},
B: function()
{
var test='test';
var result='t1';
var self = this;
var C = function()
{
self.test='test1';
.....
.....
return 'test1';
}
result=C();
return result;
}
}
If you want to assign C to 'this' object, you can also do:
A={
CA: function()
{
this.B();
},
B: function()
{
var test='test';
var result='t1';
var self = this;
this.C = function()
{
self.test='test1';
.....
.....
return 'test1';
};
result= this.C();
return result;
}
}
Solution for calling methods from another method. (Essentially the pointer "this" must be assigned to a variable and the new variable used in place of this.)
function myfunction(){
var me = this;
me.method1 = function(msg){ alert(msg); }
me.method2 = function(){
me.method1("method1 called from method2");
}
}
var f as new myfunction();
f.method2();
This example shows how one can call a method from within another method or from outside using an instance of the function.