If I do this in javascript
var A = function() {
alert(this.foo);
};
A["foo"] = "bar";
A();
I expect to alert bar but I get undefined, does anyone know how I can make this work?
Thanks
The value of this is the object upon which the method was called (unless you make use of the new operator or something like call or bind). Since you didn't call the function as a method then it is the default object (window in a browser) unless you are in strict mode.
The only reference you have to the function in scope is A, so you can only access it via alert(A.foo).
If you had used a named function expression:
var A = function myFunction () {
then you would have had the variable myFunction locally scoped to that function which you could use instead of A.
this refers to the "parent" object of the function, not the function itself. There's no parent in the expression A(). To "make that work", you'd have to explicitly pass A as the this value:
A.call(A);
The way it's usually meant to work is this:
var A = {
alert: function () {
alert(this.foo);
}
};
A.foo = 'bar';
A.alert();
The A from A.alert() is used as this value inside alert().
var A = function() {
alert(this.foo);
};
A["foo"] = "bar";
A.call(A);
or
var A = function() {
};
A.prototype.alert = function () {
alert(this.foo);
}
var a = new A();
a["foo"] = "bar";
a.alert();
Related
I have created an object and am attaching a bunch of functions to the object. I am concerned about how the ordering of the functions effects when I can call my functions. In my example below, I must define my functions first before I can use them. My problem with this is that I cannot call init() immediately until I have defined it. Init() will contain a bunch of other functions that it will need to call, which will have to be placed above init(). So in the end, init() will have to be the very last function defined in my object. I believe this is related to Hoisting.
My question is if there is a way for me to call a function before defining it? Is there some sort of way to create a 'placeholder' function like in C?
https://jsfiddle.net/13hdbysh/1/
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
//this will error
foo.init();
foo.init = function() {
console.log('init()');
};
})();
What you're asking deals with how objects store member data. This can be seen in a weird light because of prototypal inheritance. Javascript by default will parse naked functions before they execute.
Example:
(function() {
init();
function init()
{
console.log("Init");
}
)};
This gets muddied when storing behavior as a member to an object. Because prototypal inheritances dynamic functionality you need to declare your members before accessing them. This is Javascript's main difference from traditional OOP languages.
You mentioned, "is there a way to create a 'placeholder' function like in C." You can, but not in the same way. You can assign it to a naked function and assign that to your object. Look in my example, the hello function.
Alternatively you can store the behavior on the prototype of your object and override it when necessary.
Example:
function hello()
{
console.log("Hello my name is "+this.name);
}
(function() {
var something = function(name) {
this.name = name;
};
something.prototype.initTwo = function() {
console.log("My Name is: "+this.name);
};
var thingOne = new something("Thing One");
thingOne.init = "SomeThing";
var thingTwo = new something("Thing Two");
thingTwo.init = function() {
console.log(this.name);
};
thingTwo.initTwo = function() {
console.log("SomethingTwo is Named: "+this.name);
};
thingTwo.hello = hello;
console.log(thingOne.init);
thingTwo.init();
thingOne.initTwo();
thingTwo.initTwo();
thingTwo.hello();
}) ();
Demo: Fiddle
Documentation on objects in javascript.
Try using similar IIFE pattern
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
//this will error
// foo.init();
foo.init = (function _foo() {
console.log('init()');
this.init = _foo;
return this.init
}).call(foo);
foo.init()
})();
jsfiddle https://jsfiddle.net/13hdbysh/2/
I am not sure why would you wanna call it before it is defined but here is how to do it:
foo = window.foo || { init: function() { } };
How about declaring it as a local variable first.
(function() {
foo = window.foo || {};
//this will not error
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.helloWorld();
var initFunction = function() {
console.log('init()');
};
//this will no longer error
initFunction();
foo.init = initFunction;
})();
Init() will contain a bunch of other functions that it will need to call, which will have to be placed above init().
You are operating under a misapprehension.
A function must be defined before you call it, not before you define another function which will call it later.
Just define all your functions and then start calling them.
(function() {
foo = window.foo || {};
foo.helloWorld = function() {
console.log('helloWorld()');
};
foo.init = function() {
console.log('init()');
};
foo.init();
foo.helloWorld();
})();
As far as hoisting is concerned, function declarations (you only have function expressions) are hoisted, but they create locally scoped variables, not object properties. You would have to assign them to object properties before you could call them as such, and that assignment wouldn't be hoisted.
It's throwing an error because you're calling the method init() before it's declared.
This way will works
foo.init = function() {
console.log('init()');
};
foo.init();
Since foo is an object, you can put those functions into an object so that will be assigned to foo once window.foo is null
(function() {
foo = window.foo || {
helloWorld: function() {
console.log('helloWorld()');
},
init: function() {
console.log('init()');
}
};
//this will not error
foo.helloWorld();
foo.init()
})();
I have the following code with and without a module pattern. I have given the results right next to the execution. In the module pattern, I am able to change foo and set_inner, while in the function object (non-module), I can't change foo and set_inner.
module pattern:
var someObj = (function () {
var instance = {},
inner = 'some value';
instance.foo = 'blah';
instance.get_inner = function () {
return inner; };
instance.set_inner = function (s) {
inner = s; };
return instance; })();
someObj.get_inner();//some value
someObj.set_inner("kkkk");
someObj.get_inner();//kkk
someObj.foo;//blah
someObj.foo="ddd";
someObj.foo;//ddd
non-module:
var someObj = function () {
var instance = {},
inner = 'some value';
instance.foo = 'blah';
instance.get_inner = function () {
return inner; };
instance.set_inner = function (s) {
inner = s; };
return instance; };
someObj().get_inner();//some value
someObj().foo;//blah
someObj.foo="aaa";
someObj().foo;//blah
someObj().set_inner("kkk");
someObj().get_inner();//some value
Any help is much appreciated. Thanks!
Your "module" example creates a single object, referred to by instance. The anonymous function is immediately invoked, and returns that object. So someObj refers to instance.
Your "non-module" example creates a new object each time you invoke it. The anonymous function is not immediately invoked. Instead, it has to be called every time you want to use it.
It would behave the same way if you assigned the return value to a variable and referred to that, instead of repeatedly invoking someObj:
var obj = someObj();
obj.get_inner(); //some value
obj.foo; //blah
obj.foo="aaa";
obj.foo; //aaa
//etc...
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 want to be able to assign a property to a function inside the function itself. I do not want to assign it to the object of invocation. So I want the equivalent of doing this:
var test = function() {
return true;
};
test.a = 'property on a function';
alert(test.a);
Instead of this, where the property is assigned to a global object:
var testAgain = function() {
this.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(window.a);
Edit: To clarify, I'm wondering if there's something like this:
var test = function() {
function.a = 'property on a function';
};
alert(test.a); // returns 'property on a function'
Without knowing that the function is called test or having to execute it.
I know of course this isn't valid syntax
[is there a way to set a property on a function] without knowing that the function is called test or having to execute it.
Emphasis mine.
You can set a property on a function without knowing what its global variable name is necessarily going to be, however you do have to have a reference to the function in one way or another.
The module pattern is as close of a fit as I can think of:
window.test = (function () {
//the function could be named anything...
function testFn() {
...code here...
}
//...so long as the same name is used here
testFn.foo = 'bar';
return testFn;
}());
window.test.foo; //'bar'
The outer closure prevents testFn from being accessed anywhere globally, so all other references will have to use window.test.
This part of the answer is associated with the prior version of the question.
The simplest way of doing this is to use a named function:
var test = function testFn() {
testFn.foo = 'bar';
return true;
};
test.foo; //undefined
test();
test.foo; //'bar'
A better way of doing this is to use the module pattern so that you don't accidentally create issues with global leakage:
var test = (function () {
function ret() {
ret.foo = 'bar';
return true;
}
return ret;
}());
test.foo; //undefined
test();
test.foo; //'bar'
var testAgain = function() {
arguments.callee.a = "this property won't be assigned to the function";
return true;
};
testAgain();
alert(testAgain.a);
You can do this by simple using the name to assign the property like this:
var test = function () {
test.a = 'a';
return true;
};
When test is invoked, the property will be set.
Demo
You could use arguments.callee, as su- said, but that's considered really bad practice. Also, it won't work in strict mode.
var test = function() {
test.a = 'a';
};
Or you can use prototypes, read more here.
This question already has answers here:
JavaScript: Reference a functions local scope as an object
(5 answers)
Is there a Javascript variable that represents local scope? Like global?
(1 answer)
Closed 8 years ago.
I know that variables are properties of other objects. For example:
var myVar = 'something';
is a property of the window object (if it is in the global scope of course).
if I want to find the variable's object, I just use the this variable. But:
function f() {
var myVar2 = 'something';
}
Which object does myVar2 belongs to? (myVar belongs to window object, but what about myVar2?)
I would like to know that, thanks.
It doesn't belong to an object. It belongs to the scope of the function f. You access it by doing myVar within f. You cannot access it outside of f.
If you did
function f() {
this.myVar = 1;
}
now you can do
var myF = new f();
myF.myVar
indeed, this how user defined objects are sometimes defined.
myVar2 belongs to the local scope (of f), and myVar the global scope.
var does some interesting things. var statements are hoisted to the top of their functional scope. The var's functional scope is whatever function it happens to be in.
JavaScript doesn't have block-level scope, which means that:
(function () { //a closure to create new scope
var foo;
foo = 1;
if (condition) {
var bar;
bar = 3;
}
}());
...is equivalent to...
(function () {
var foo,
bar;
foo = 1;
if (condition) {
bar = 3;
}
}());
If the var statement has no parent, it will instead add the variable as a property to the global context, which in web browsers happens to be window.
This is the only time that using var will create a property. If want to create a property of an object, you simply have to set it:
(function () {
var foo;
foo = {};
foo.bar = 'baz'; //this creates the `bar` property on `foo`
}());
JavaScript is a prototypal language with prototypal inheritance. Functions are first-class objects (because JavaScript isn't racist against functions). This means that functions can be used just like any other object.
You can set them:
(function () {
var foo;
//foo is now a function
foo = function () {
alert('Hello World');
};
}());
You can set properties on them:
(function () {
var foo;
foo = function () {
alert('Hello World');
};
foo.bar = 'baz'; //this works just fine
}());
You can even pass them as parameters:
(function () {
var foo,
bar;
foo = function () {
alert('Hello World');
};
bar = function (c) {
c();
};
bar(foo); //guess what this does?
}());
Another cool thing that functions do, is they act as constructors. All functions are inherently constructors, you just need to call them using the new keyword:
(function () {
var foo; //case sensitive
//it doesn't matter whether you use `function Foo`
//or `var Foo = function...`
function Foo() {
alert('Hello World');
}
foo = new Foo();
foo.bar = 'baz';
}());
The important detail in using constructors is that the function's context (this) will be set to the object created by the constructor. This means that you can set properties on the object within the constructor:
(function () {
var foo;
function Foo() {
this.bar = 'baz';
}
foo = new Foo();
alert(foo.bar); //'baz'
}());