1
var Car = function () {
    this.wheels = 4;
};

var car = new Car();
console.log(car.wheels);

I'm new to javascript and I'm trying to understand the concept of scope.

Here Car is assigned with a function which we call a constructor. And var car = new Car(); creates a instance of a so called Car class.

I think var car = new Car() is actually creating a function and we use it to mock an instance variable in conventional OOP languages.

If that is right, var car should be a function and has its own 'scope' and we can not access its variables outside.

So why the last expression can get the value of car.wheels and print the value? It is called from the global scope!?

cнŝdk
  • 28,676
  • 7
  • 47
  • 67
jinglei
  • 2,609
  • 6
  • 21
  • 39
  • No, it's not a function. What makes you think so? – Oriol Dec 10 '16 at 10:35
  • @Oriol In JS functions are also objects. So car is an object without doubt. But I think beyond that it is a 'function' and it has its scope. So I think it's a function more specifically. – jinglei Dec 10 '16 at 10:39
  • Your logic is wrong. "In JS functions are also objects" does not imply "In JS objects are also functions". `car` is not a function, `Car` is. `car` does not have any function-like behavior. – Oriol Dec 10 '16 at 10:41
  • Why can it retrieve the thing you explicitly asked for?!! Because that's the sole reason they exist and the only thing that makes them Useful. `var car` is your *global* variable which refers to the object you've just constructed, and this object (who's handle is 'car') of course will have wheels property who's value is number 4. – Bekim Bacaj Dec 10 '16 at 10:44
  • @Oriol I agree that "In JS objects are also functions" is wrong. I think it is because I consider car is a 'function object' but not an 'conventional' object that lead to my original question. All I can think of is when `var car = new Car()` is executed, the function assigned to `Car` variable is called. And `car` is assigned with something. What happens when `new Car()` is executed? It doesn't return anything? – jinglei Dec 10 '16 at 10:52
  • `new Car()` is more or less like `Car.call(Object.create(Car.prototype))`. See [What is the 'new' keyword in JavaScript?](http://stackoverflow.com/q/1646698/1529630) – Oriol Dec 10 '16 at 10:58
  • @Jinglei.Y for additional information to Oriol comment writing `var car = new Car()` is similar to writing `var car = {wheels : 4}`, I hope you get it. – cнŝdk Dec 10 '16 at 11:01

3 Answers3

2

Questions:

I think var car = new Car() is actually creating a function and we use it to mock an instance variable in conventional OOP languages.

If that is right, var car should be a function and has its own 'scope' and we can not access its variables outside.

Answer:

These two statements are wrong because you are confusing objects and functions here.

Explanation:

In fact in your case Car is a Constructor which is also a function, but car in var car = new Car() is not a function like you are saying but it's an object created using the Car constructor, because the new keyword creates a new instance object using the Car constructor.

For example, if we write:

var today = new Date();
console.log(typeof today); //returns object

var reg = new RegExp('\\w+');
console.log(typeof reg); //returns object

We got two objects here because we used the Date and RegExpconstructors to create two new objects.

Difference between object and function in JS:

To see the diffrerence between Object and function, run this snippet:

var Car = function () {
    this.wheels = 4;
};
console.log("Car.wheels: "+Car.wheels);//You will get undefined

var car = new Car();
console.log("car.wheels: "+car.wheels);//You will get 4

Because Car is a constructor/function and its properties aren't accessible outside its scope but car is an object so we can access its properties.

cнŝdk
  • 28,676
  • 7
  • 47
  • 67
  • But in JS functions are also objects? – jinglei Dec 10 '16 at 10:34
  • Yes in JavaScript everything can be seen as an object, but if you write `var Car = function () { this.wheels = 4; };` then `console.log(typeof Car);` you will get `"function"` . – cнŝdk Dec 10 '16 at 10:37
  • @Jinglei.Y But not all objects are functions! – Oriol Dec 10 '16 at 10:37
  • @Oriol Yes. I think you mean those basic types like numbers and strings, etc. – jinglei Dec 10 '16 at 10:40
  • @Jinglei.Y Numbers and strings are not objects (and therefore are not functions). Number objects and string objects are objects (and additionally are not functions). But I didn't mean special objects like these, I mean the great majority of ordinary objects are not functions. `[]` is not a function, `{}` is not a function `new function(){}` is not a function, `/./` is not a function. – Oriol Dec 10 '16 at 10:44
  • To correct you @Oriol objects **are not** functions, but I think you meant that in JavaScript we can create objects using a Constructor like this case but we can also create objects simply like this `var person = {name: "Ali", age:30};` but both of them aren't functions. – cнŝdk Dec 10 '16 at 10:48
  • @chsdk @Jinglei.Y All objects are instances of a function. `Object instanceof Function; >> true;` & `Object.constructor >> function Function()`. JavaScript is a Functional Language. – Bekim Bacaj Dec 10 '16 at 10:51
  • 1
    I think I've misunderstood the `new` operator. I've just looked up the doc and it says **The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.** I thought it copies something, this is why I thought car is a function. – jinglei Dec 10 '16 at 11:04
  • @BekimBacaj No in fact not all objects are instance of function, if you write `var Car = function (wheels) { var _wheels = wheels; // Function scope this.wheels = _wheels; // context }; ` then `Car instanceof Function` you will get `true`, but this works only with objects created using Constructors if you write `var person = {name : "John", age:14};` then `person instanceof Function` you will get `false`. – cнŝdk Dec 10 '16 at 11:08
  • @Jinglei.Y Yes that's it. glad you understood it. – cнŝdk Dec 10 '16 at 11:09
  • @chsdk Yes all objects are instances of a function; primitives and literals are not they are handled by the mediator, top-Object call for proper type constructor (which is a function just like any other constructor) in a second hand derivative Function > Object > Array chain. e.g.: `[] instanceof Array >> true' > Àrray instanceof Object >> true` > `Object instanceof Function >> true` – Bekim Bacaj Dec 10 '16 at 11:25
1

The properties you define on an Object with this or prototype is not private. They can be accessed and modified by possibly any function that has a reference to the instance. Read this article to get an idea of private variables in javascript.

The below example shows one possible way on how you can make wheels private and expose the getWheels function as a public getWheelsPublic. There are more patterns that is documented here.

var Car = function(wheels) {
  var privateWheels;

  function setWheels(wheels) {
    privateWheels = wheels;
  }

  function getWheels() {
    return privateWheels
  }
  setWheels(wheels);

  return {
    getWheelsPublic: getWheels
  }
};

var car = new Car(4);
var car2 = new Car(3);
console.log(car.getWheelsPublic(), car2.getWheelsPublic()); //4 3
console.log(car.privateWheels); //undefined

If you take a look at the instance you created in the result of below snippet ({"wheels": 4}), you can instantly see that wheels is available as a property in that Object and not associated with lexical scope of the function. Also notice that privateOwner in the lexical scope is not available from outside.

var Car = function () {
    this.wheels = 4;
    var privateOwner = "SabithPocker"
};

var car = new Car();
console.log(car); //{"wheels": 4} 
sabithpocker
  • 14,235
  • 1
  • 36
  • 69
  • Thanks. It seems you have a misunderstanding of my question. I know that instances can have their own properties. Actually my question is **why these properties are accessible from global scope as they are in a function scope of their own?** I think they are supposed to be local variables? – jinglei Dec 10 '16 at 09:59
  • It is mainly because the properties defined by `this` in your case are added as properties on that `object` and is not private. It doesn't follow lexical scope. But variables declared with `var` will follow lexical scoping as you want. – sabithpocker Dec 10 '16 at 10:25
  • So to answer the question, they are not in a function/lexical scope of `car` but just properties of car `object` which are accessible in all places where a reference to `car` is available. – sabithpocker Dec 10 '16 at 10:45
1

You are right in that a function defines a scope and that all variables are local to it. However, functions have also context, which is what you access through the this operator. Context is object-based, and objects in JS are created by means of prototypes. In your example, the function acts as the constructor of the object, with this being the object context. So when you do:

var Car = function (wheels) {
  var _wheels = wheels; // Function scope
    this.wheels = _wheels; // context
};

Car.prototype.getWheels = function(){
  return this.wheels; // Context
 }

var car = new Car(4);
var car2 = new Car(3);
console.log(car.wheels, car2.wheels);//4 3

console.log(car.getWheels())

you are using the context.

You can read more about this in this article.

martinarroyo
  • 8,517
  • 3
  • 30
  • 65