I have been working with javascript for a while and always used this notation to create objects
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
});
but now I have a project where I use AngularJs and the javascript don't recognize it. I can use this one
var className = (function() {
this.property = 1; //Example of a property
this.method = function() {
//Example of a method
};
});
Is there any reason for the first one not working? In my experience I prefer the first one better
[Edit]
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
})();
var className = (function() {
var property = 1; //Example of a property
var method = function () {
//Example of a method
};
});
In this example you're not actually creating anything that surmounts to a property and/or method. You're simply assigning a function to the variable className, and within that function you're creating two more variables. Variables are function-scoped, and by definition, won't be visible outside the function.
If you use AngularJS, then there are different scopes and understanding of OOP. You should probably must know $scope which is the scope for Angular objects, methods etc. Please check the documentation, also read more about Angular scopes.
In your case, you should have this code in some controller or service (factory, directive) and have something like this:
angular.module('myapp', [])
.controller('MyCtrl', ['$scope', function($scope) {
$scope.myvar = 'hello';
$scope.mymethod = function() {
console.log($scope.myvar);
};
}])
Those 2 examples do 2 very different things.
In the first, you're not actually creating any properties on the newly created object when calling className(). Anything declared using var in a function is just a locally-scoped value to that function, meaning you can't access it once you leave that function.
The second will actually create the properties property and method on the newly created object. However, when defining constructor functions it's much more common to do it like this:
function ClassName() {
this.property = 'some property value'
}
Constructor functions are typically capitalized, but this is just a style guide thing.
And then define member functions on the constructor's prototype like this:
ClassName.prototype.method = function() {
// function body where "this" refers to an instance of ClassName
}
Then you can use the constructor like this:
var someObject = new ClassName()
To understand this behavior, you need to understand how JavaScript handles scope.
The only scope within JavaScript is function scope. To understand what this means, consider the other types of scope you see in other programming languages, such as loops, classes, and if-else statements. When you create a variable within a scope, it can not be accessed outside that scope.
Because the only JavaScript scope is function scope, these two methods are functionally identical:
function myFunc(){
var x = 5; // variable declared outside loops
for(var i = 0; i < x; i++){ // iterator variable declared in loop params
var y = i; // variable declared inside a loop
for(var i = 10; i > 6; i--){
var z = i; // variable declared inside another loop
}
}
}
function myFunc(){
var x, i, y, z; // all variables declared at beginning of function
x = 5;
for(i = 0; i < x; i++){
y = i;
for(i = 10; i > 6; i--){
z = i;
}
}
}
Notice that in JavaScript, it's a logic error to use the same iterator variable in for loops in the same scope, since they will refer to the same variable (there's no "loop scope" to distinguish them).
On the other hand, function scope can be used to prevent variable names from colliding, since variables can't be accessed outside their scope.
Notice in the example below we have two different variables named x. They are different because they exist in different function scopes.
var x = "Outer Scope";
(function(){
var x = "Inner Scope";
alert(x); // output: "Inner Scope"
})();
alert(x); // output: "Outer Scope"
There's no way for the outer scope to access the value of x in the inner scope.
That brings us to the JavaScript way of creating object-like syntax.
In your first example, the variables property and method cannot be accessed outside of the "constructor" or "class definition" (or whatever you want to call the function you'll use to create objects) because they're wrapped up in a function scope. You can practically think of them as private members.
In your second example, you're using the this keyword to attach the variables as attributes of the object returned by your "constructor". The object attributes can be accessed by code outside the function scope. Think of them as public members.
If it helps put things into an object-oriented frame of reference, you can even use that syntax to provide getters and setters (accessors and mutators), like so.
var className = function() {
var property = 1;
this.getProperty = function(){return property;};
this.setProperty = function(value){property = value;};
};
var obj = new className();
obj.getProperty(); // 1
obj.setProperty(200);
obj.getProperty(); // 200
typeof(obj.property); // "undefined"
The getProperty() and setProperty() functions are able to access the property because they were defined within the same function scope; to understand this more clearly, look up "closures."
From a performance perspective, you may not want to have many functions defined in your "class definition" as above, since that results in each instance of the object having its own copy of the function (which increases the amount of memory each object requires). Instead, you can attach methods to the prototype of the function, so the methods are defined once.
className.prototype.getDouble = function(){return this.getProperty()*2;};
obj.getDouble(); // 400
A big thing to note is that prototype functions are also bound by function scope, so they can't access variables that you defined in the "class definition."
className.prototype.getTriple = function(){return property*3;};
obj.getTriple(); // ERROR: "'property' is undefined"
Related
Should 'this.' or 'var' be used to create variables in a Javascript class or does it not matter which is used. Obviously those defined with this. will be accessible from outside the object whereas those defined with var will not but are there any other differences?
function myClass() {
this.count = 0;
this.oTimer = null;
this.getCount = function() { return(this.count); }
}
oMyObj = new myClass();
oMyObj.getCount(); // returns 0
as opposed to
function myClass2() {
var count = 0;
var oTimer = null;
this.getCount = function() { return(count); }
}
oMyObj = new myClass2();
oMyObj.getCount(); // returns 0
Trying to explain a little bit more in detail than Dominique in the comments:
if you use the var keyword, the variable is only valid in the scope they are run. This means that after the constructor is run (the function body), the variables get lost (as they were only valid inside the constructor).
If you want to access the variables outside of the constructor (e.g. member-methods), you have to bind the variables to the class itself via the this keyword. Now their scope is the class itself, not just the constructor.
Edit:
Explaining further: while you can use the variables declared with var inside of methods that you also declared inside the constructor because they are defined in the same scope (see example of Question), it is not possible to access them through any other added methods that you add via Function.prototype.
To show this, I have created a little JSFiddle example
So it is generally better practice to define all variables of a class (that you don't only intent to use as temporary variables inside the constructor) with the this keyword.
If functions are objects in javascript, why can't I access the function scope defined variables?
I understand that in the code:
// variable test assigned an anonymous function
var test = function(){
var x = 5;
};
console.log(test.x); // undefined
// Even when the function is explicitly named:
function test(){
var x = 5;
}
console.log(test.x); // undefined
I don't need to get this working or anything; I just need to understand why functions are like this.
Thanks.
This would be one way to accomplish what you are trying:
function test() {
this.x = 5;
}
var foo = new test();
console.log(foo.x);
Using var x rather than this.x just declares a local variable
I believe it is because those variables only exist within the scope of the function you have defined. Outside the scope of that function they do not exist.
They are the equivalent of private members in a class of an object oriented language.
Alternatively you could have
function test() {
this.x = 5;
}
var testInstance = new test();
console.log(test.x);
Functions are objects, but that doesn't mean that any variable declared inside the function becomes a property of that function object. In fact, that would be terrible because you wouldn't be able to run a function more than once (since the second time, the variables would start with different values).
You can assign a property to a function object like this:
var test = function () {};
test.x = 5
The variable is visible only in the function and it is possible to access it only within the function, you can use global variable and then edot it insode the function.
You have created Local variables. Local variable can only be accessed within the function.
Try to understand about Local & Global JavaScript Variables
Local JavaScript Variables
Variables declared within a JavaScript function, become LOCAL to the function.
Local variables have local scope: They can only be accessed within the function.
function myFunction() {
var name = "roy";
// code here can use name
}
Global JavaScript Variables
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.
var name = "roy";
// code here can use name
function myFunction() {
// code here can use name
}
var someName = function(){var x ...} /// only has local scope.
What is the scope of variables in JavaScript?
Will describe it better than I can. Good job on being curious and motivated.
$(document)/ready(function(){
if (this == that) {
var myobject = {};
var variable = 55;
function dothisandthat(variable);
alert(JSON.stringify(myobject));
}
})
function dothisandthat(variable) {
//Do something
myobject["first"] = variable + 5;
myobject("second") = variable + 10;
}
How can i get myobject to be used in my function, and then call the object outside of the function again?
It can be globally available if you just do myobject = {} or window.myobject = {}, or even $.myobject = {}. Attach it to some global object like window, or since you are using JQuery, the JQuery $ object, and then you can use that throughout.
Or as #Pointy said, just add the parameter to the method:
function dothisandthat(variable, myObject) {
Well, with an object oriented approach, you would usually tell the object to modify it's internal state, which solves your scoping problems at the same time.
function MyObject() {
this.first = 0;
this.second = 0;
}
MyObject.prototype.doThisAndThat = function (variable) {
this.first = variable + 5;
this.second = variable + 10;
};
$(document).ready(function () {
//...
var myObject = new MyObject();
myObject.doThisAndThat(55);
alert(JSON.stringify(myObject));
//...
});
However, if you want to use a functional approach (data and behavior lives separately) you must make myObject available in the doThisAndThat's scope. There are a few ways to do this:
Pass the object as an argument to the function. That's usually the way I prefer since it makes dependencies explicit.
Please note that a pure functional approach would not mutate the object passed-in to the function, but would return a modified copy of the object since data structures are usually immutable.
Rely on a closure. In this case, you would simply have to move the doThisAndThat function declaration inside the document ready callback.
Rely on global variables or well-know objects. I would avoid this solution most of the time since it makes your dependencies hidden and your code harder to test.
If I were to make a new function using the Function constructor, how could I give it a non-temporary scope to access besides window (meaning the scope only has to be evaluated once, not every time the function is called)? The purpose is to construct multiple variables that require some pretty costly calculations, and I don't want to reconstruct them every time the function is called, but I also don't want to store them in window. Any ideas?
You could bind your function to the specific context using bind keyword:
var context = {};
var f = new Function("args", "return this").bind(context);
f(); // context
Since bind is defined in ECMA 5th, it may not be present in all browsers, here's a workaround
For the above described purpose, you use static functions. You cannot prevent scope from being evaluated at every call, because this is the way JavaScript works, but you can speed it up by not having window in the scoping chain.
var namespace = {};
namespace.someMethod = function() {
// do something here.
};
Now anywhere in your code, you can call that method by using namespace.someMethod();. Just be careful. The above is a static method. You can call it without instantiating. But you MUST NOT use this.property inside a static function. It is a potentially very dangerous operation, as it may give an extension access to the global object and basically un-restricted permissions.
And the above is a static JavaScript method. It does not have window in the scoping chain.
Here's how to create a constructor using the same pattern. When you want to use a constructor, you always instantiate before using. For that you have the new keyword.
var namespace = {};
namespace.coordinate = function(x, y) {
this.x = x;
this.y = y;
};
namespace.coordinate.prototype.addCoordinates = function() {
return this.x + this.y;
};
Now anywhere in your code you can do:
var coordinateObject = new namespace.coordinate(5,10);
// you have created a new instance.
alert(coordinateObject.addCoordinates());// will alert 15;
// now you can make as many as you want. They will behave as instances.
// This means they do not interfere with each other in any way.
// They just have the same properties and methods, but the instance values
// Can be entirely different.
var secondCoordinateObject = new namespace.coordinate(10, 25);
alert(secondCoordinateObject.addCoordinates());// will output 35.
You have successufully created an instance of your namespace.coordinate class. Using the pattern I gave you, you can replicate almost the entire functionality of Java or C or any other Object Oriented language.
var yourNamespace = {
func1: function() {
},
func2: function() {
}
};
...
yourNamespace.func1();
you can call the function that you want by calling the function from name space like this yourNamespace.func1();
The ever-growing method of creating, storing, hiding, revealing, and grouping variables & functions is through the magic of "closures", Javascript's most powerful and yet unsung feature:
var groupObj = (function (setUp) {
// maintained by reference, hidden
var _priVar = setUp * 2;
// maintained by reference, revealed (through returned object)
var _pubVar = 8;
var _pubFunc = function (x) {
_priVar += x;
_pubVar += x;
}
var lostVar = setUp * 99; // not referenced, hidden, so evaporates!
return {
'pubVar' : _pubVar,
'pubFunc' : _pubFunc
}
}(4)); // runs immediately with 4 as setUp, revealing pubVar & pubFunc
Then...
groupObj.pubFunc(7); // runs public function, adds 7 to both variables
alert('public variable: ' + groupObj.pubVar); // alerts public variable
A closure occurs whenever there is a function inside of another function. A variable inside of the outter function will be maintained so long as it is referenced by the inner function, kind of a "no-mans land" where a variable is forced to exist by a reference to it from a lower scope, but is hidden from the higher scope due to the innate principles of Javascript.
There are a few other ways to use closures, replacing the object constructor, one-off conflict-free private functions, and more. There are many posts here about them.
What is the difference between
function person(first_name, last_name) {
this.first = first_name
this.last = last_name
}
and this:
function person(first_name, last_name) {
var first = first_name
var last = last_name
}
Why only the first one makes person.first & person.last accessible outside the function?
The this keyword within a function is called the invocation context.
1) If you define your function as a member of an object (a method):
myObject.someMethod = function() { this.x = 2; };
then the invocation context, this, is the object to which the method is being added, myObject. So after calling myObject.someMethod(); above, myObject.x is then 2. The member x is undefined until you call the method, unless you defined it before.
2) If you use your function as a constructor with the new keyword, then this refers to the new object that is being created:
function MyX() { this.x = 3; };
var myX = new MyX();
You'll then have property myX.x set to 3.
Note that I called my constructor MyX(), not myX(). You should call yours Person(), not person(). It's just a convention, but it is useful to indicate that a function is meant to be used as a constructor.
3) Finally, if you use this within a function that you call as neither a method nor a constructor, then this refers to the global object (document or, equivalently, window). Note however that if you are using javascript in strict mode (which you should do), this is undefined in such a situation, which means that you basically cannot use this in a function that is not a method or a constructor.
Your specific question refers to case 2), the constructor. this.x = 3 in the constructor just sets property x of the newly created object. After some object myX is created, you can then access and modify x externally as any other object property using myX.x.
when you write constructor function ( using new) - you add properties using this.XXX
then you do :
var p = new Person('s','d');
and then you have access to p.first etc.
in the second example :
youre not creating any properties..
youre only creating private variables.
so you cant access them...
By using this.something you're saying that THIS is an object and something is his property.
By using var, you're saying that it's just a variable and not a property.
More information about variable vs property:
http://javascriptweblog.wordpress.com/2010/08/09/variables-vs-properties-in-javascript/
Because of function scope.
A variable lifetime is between the curly braces of the function. The this keyword allows to access the function properties outside of it.
Definitely take a look at this link: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope
'var' keyword make a variable scoped. In the last example var first and var last create variable accessible only in the scope of the function. You can see this as a local variable in a constructor.
when in javascript you declare a variable as
var variable
it only exists inside the method where you declared it. If you want a variable to be accessible for everyone (that is, global) it has to be declared without the 'var' part
You do not necessarily have to use this. It'd also work fine if you've got a structure like this:
Person = function(first_name, last_name) {
var first, last;
create(first_name, last_name);
function create(first_name, last_name) {
first = first_name
last = last_name
}
return {
firstName: first,
lastName: last
}
}