BCasaleiro
BCasaleiro

Reputation: 139

Javascript Class properties and methods work differently

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  
  };
})();

Upvotes: 0

Views: 194

Answers (4)

Thriggle
Thriggle

Reputation: 7049

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"

Upvotes: 0

Michael B.
Michael B.

Reputation: 351

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()

Upvotes: 0

Novitoll
Novitoll

Reputation: 846

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);
     };
  }])

Upvotes: 0

jmar777
jmar777

Reputation: 39649

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.

Upvotes: 1

Related Questions