While making a JavaScript class function, I’m using this. A lot. But while using that, it’s making me wonder whether it would’ve made a difference to use var instead.
var MyClass = function() {
this.x = 4;
return {
getVal: this.x
};
}
versus the same thing with the use of var:
var MyClass = function() {
var x = 4;
return {
getVal: x
};
}
What’s the difference and when should I use which?
The same question applies to the class syntax:
class MyClass {
constructor(){
const x = 4;
}
}
versus
class MyClass {
constructor(){
this.x = 4;
}
}
Identifiers with this become public properties, whereas those with var become private variables.
Nowadays, const should be used instead of var; if you can’t use const for a specific variable, use let instead.
The access semantics are the same.
When using an identifier with the this keyword, like this.x = 4;, you’re setting a property with the key "x" and the value 4 on the object referenced by this. Since this refers to the instance in the context of a class, such properties become instance members of the class, which means they will be available in each newly created instance of that class. When you use this, it means that your intention is to use it in a class, so you need to instantiate it using the new keyword as shown below.
Example
function Foo() {
// Variables, scoped to the function. Private access.
const bar = 'I am bar';
// Properties, set on the instance. Public access
this.baz = 'I am baz';
this.secretBar = () => `It’s a secret to everybody: ${bar}.`;
}
const f = new Foo();
console.log(f.bar); // undefined
console.log(f.baz); // "I am baz"
console.log("bar" in f); // false; f does not have the property "bar".
console.log(f.secretBar()); // "It’s a secret to everybody: I am baz.";
// `secretBar` is in the scope of `Foo`, so it has access to its variables.
While making a JavaScript class function, I’m using this.
A lot.
But while using that, it’s making me wonder whether it would’ve made a difference to use var instead.
There is a significant difference. You should not create variables with the this keyword that you don’t want to appear in instances of your class, unless otherwise needed.
You can access this.x with myClass.x, but you can't do that for var x case. This is all about encapsulation.
If you are not going to need to do inheritance, closures (the var case) and objects (the this case) basically do the same thing and are roughly interchangeable.
Differences to keep in mind:
When you use "this" the constructor needs to be called with "new" and methods need to be called with .call if you store them on a variable or pass them as a callback.
There might be performance differences if you instantiate lots of objects (current engines may with objects better - but only if you put the methods in the prototype instead of setting them in the constructor)
Variables declared with "var" are private and cannot be accessed outside the function. Sometimes this is OK but this can stop you from doing inheritance (there is no notion of "protected in Javascript")
Expressions like this.x refer to properties; they are like instance variables. These variables have public scope. They work as class variables in object oriented programming.
On the other hand, var x; has limited scope. These are variables that behave like private instance variables and are accessible within the local scope.
Related
In C++, the language I'm most comfortable with, usually one declares an object like this:
class foo
{
public:
int bar;
int getBar() { return bar; }
}
Calling getBar() works fine (ignoring the fact that bar might be uninitialized). The variable bar within getBar() is in the scope of class foo, so I don't need to say this->bar unless I really need to make it clear that I'm referring to the class' bar instead of, say, a parameter.
Now, I'm trying to get started with OOP in Javascript. So, I look up how to define classes and try the same sort of thing:
function foo()
{
this.bar = 0;
this.getBar = function() { return bar; }
}
And it gives me bar is undefined. Changing the bar to this.bar fixes the issue, but doing that for every variable clutters up my code quite a bit. Is this necessary for every variable? Since I can't find any questions relating to this, it makes me feel like I'm doing something fundamentally wrong.
EDIT: Right, so, from the comments what I'm getting is that this.bar, a property of an object, references something different than bar, a local variable. Can someone say why exactly this is, in terms of scoping and objects, and if there's another way to define an object where this isn't necessary?
JavaScript has no classes class-based object model. It uses the mightier prototypical inheritance, which can mimic classes, but is not suited well for it. Everything is an object, and objects [can] inherit from other objects.
A constructor is just a function that assigns properties to newly created objects. The object (created by a call with the new keyword) can be referenced trough the this keyword (which is local to the function).
A method also is just a function which is called on an object - again with this pointing to the object. At least when that function is invoked as a property of the object, using a member operator (dot, brackets). This causes lots of confusion to newbies, because if you pass around that function (e.g. to an event listener) it is "detached" from the object it was accessed on.
Now where is the inheritance? Instances of a "class" inherit from the same prototype object. Methods are defined as function properties on that object (instead of one function for each instance), the instance on which you call them just inherits that property.
Example:
function Foo() {
this.bar = "foo"; // creating a property on the instance
}
Foo.prototype.foo = 0; // of course you also can define other values to inherit
Foo.prototype.getBar = function() {
// quite useless
return this.bar;
}
var foo = new Foo; // creates an object which inherits from Foo.prototype,
// applies the Foo constructor on it and assigns it to the var
foo.getBar(); // "foo" - the inherited function is applied on the object and
// returns its "bar" property
foo.bar; // "foo" - we could have done this easier.
foo[foo.bar]; // 0 - access the "foo" property, which is inherited
foo.foo = 1; // and now overwrite it by creating an own property of foo
foo[foo.getBar()]; // 1 - gets the overwritten property value. Notice that
(new Foo).foo; // is still 0
So, we did only use properties of that object and are happy with it. But all of them are "public", and can be overwritten/changed/deleted! If that doesn't matter you, you're lucky. You can indicate "privateness" of properties by prefixing their names with underscores, but that's only a hint to other developers and may not be obeyed (especially in error).
So, clever minds have found a solution that uses the constructor function as a closure, allowing the creating of private "attributes". Every execution of a javascript function creates a new variable environment for local variables, which may get garbage collected once the execution has finished. Every function that is declared inside that scope also has access to these variables, and as long as those functions could be called (e.g. by an event listener) the environment must persist. So, by exporting locally defined functions from your constructor you preserve that variable environment with local variables that can only be accessed by these functions.
Let's see it in action:
function Foo() {
var bar = "foo"; // a local variable
this.getBar = function getter() {
return bar; // accesses the local variable
}; // the assignment to a property makes it available to outside
}
var foo = new Foo; // an object with one method, inheriting from a [currently] empty prototype
foo.getBar(); // "foo" - receives us the value of the "bar" variable in the constructor
This getter function, which is defined inside the constructor, is now called a "privileged method" as it has access to the "private" (local) "attributes" (variables). The value of bar will never change. You also could declare a setter function for it, of course, and with that you might add some validation etc.
Notice that the methods on the prototype object do not have access to the local variables of the constructor, yet they might use the privileged methods. Let's add one:
Foo.prototype.getFooBar = function() {
return this.getBar() + "bar"; // access the "getBar" function on "this" instance
}
// the inheritance is dynamic, so we can use it on our existing foo object
foo.getFooBar(); // "foobar" - concatenated the "bar" value with a custom suffix
So, you can combine both approaches. Notice that the privileged methods need more memory, as you create distinct function objects with different scope chains (yet the same code). If you are going to create incredibly huge amounts of instances, you should define methods only on the prototype.
It gets even a little more complicated when you are setting up inheritance from one "class" to another - basically you have to make the child prototype object inherit from the parent one, and apply the parent constructor on child instances to create the "private attributes". Have a look at Correct javascript inheritance, Private variables in inherited prototypes, Define Private field Members and Inheritance in JAVASCRIPT module pattern and How to implement inheritance in JS Revealing prototype pattern?
Explicitly saying this.foo means (as you've understood well) that you're interested about the property foo of the current object referenced by this. So if you use: this.foo = 'bar'; you're going to set the property foo of the current object referenced by this equals to bar.
The this keyword in JavaScript doesn't always mean the same thing like in C++. Here I can give you an example:
function Person(name) {
this.name = name;
console.log(this); //Developer {language: "js", name: "foo"} if called by Developer
}
function Developer(name, language) {
this.language = language;
Person.call(this, name);
}
var dev = new Developer('foo', 'js');
In the example above we're calling the function Person with the context of the function Developer so this is referencing to the object which will be created by Developer. As you might see from the console.log result this is comes from Developer. With the first argument of the method call we specify the context with which the function will be called.
If you don't use this simply the property you've created will be a local variable. As you might know JavaScript have functional scope so that's why the variable will be local, visible only for the function where it's declared (and of course all it's child functions which are declared inside the parent). Here is an example:
function foo() {
var bar = 'foobar';
this.getBar = function () {
return bar;
}
}
var f = new foo();
console.log(f.getBar()); //'foobar'
This is true when you use the var keyword. This means that you're defining bar as local variable if you forget var unfortunately bar will became global.
function foo() {
bar = 'foobar';
this.getBar = function () {
return bar;
}
}
var f = new foo();
console.log(window.bar); //'foobar'
Exactly the local scope can help you to achieve privacy and encapsulation which are one of the greatest benefits of OOP.
Real world example:
function ShoppingCart() {
var items = [];
this.getPrice = function () {
var total = 0;
for (var i = 0; i < items.length; i += 1) {
total += items[i].price;
}
return total;
}
this.addItem = function (item) {
items.push(item);
}
this.checkOut = function () {
var serializedItems = JSON.strigify(items);
//send request to the server...
}
}
var cart = new ShoppingCart();
cart.addItem({ price: 10, type: 'T-shirt' });
cart.addItem({ price: 20, type: 'Pants' });
console.log(cart.getPrice()); //30
One more example of the benefits of the JavaScript scope is the Module Pattern.
In Module Pattern you can simulate privacy using the local functional scope of JavaScript. With this approach you can have both private properties and methods. Here is an example:
var module = (function {
var privateProperty = 42;
function privateMethod() {
console.log('I\'m private');
}
return {
publicMethod: function () {
console.log('I\'m public!');
console.log('I\'ll call a private method!');
privateMethod();
},
publicProperty: 1.68,
getPrivateProperty: function () {
return privateProperty;
},
usePublicProperty: function () {
console.log('I\'ll get a public property...' + this.publicProperty);
}
}
}());
module.privateMethod(); //TypeError
module.publicProperty(); //1.68
module.usePublicProperty(); //I'll get a public property...1.68
module.getPrivateProperty(); //42
module.publicMethod();
/*
* I'm public!
* I'll call a private method!
* I'm private
*/
There's a little strange syntax with the parentless wrapping the anonymous functions but forget it for the moment (it's just executing the function after it's being initialized). The functionality can be saw from the example of usage but the benefits are connected mainly of providing a simple public interface which does not engages you with all implementation details. For more detailed explanation of the pattern you can see the link I've put above.
I hope that with this :-) information I helped you to understand few basic topics of JavaScript.
function Foo() {
this.bar = 0;
this.getBar = function () { return this.bar };
}
When you call the function above with the new keyword - like this...
var foo = new Foo();
... - a few things happen:
1) an object is created
2) the function is executed with the this keyword referencing that object.
3) that object is returned.
foo, then, becomes this object:
{
bar: 0,
getBar: function () { return this.bar; }
};
Why not, then, just do this:
var foo = {
bar: 0,
getBar: function () { return this.bar; }
};
You would, if it's just that one simple object.
But creating an object with a constructor (that's how it's called) gives us a big advantage in creating multiple of the "same" objects.
See, in javascript, all functions are created with a prototype property [an object], and all objects created with that function (by calling it with the new keyword) are linked to that prototype object. This is why it's so cool - you can store all common methods (and properties, if you wanted to) in the prototype object, and save a lot of memory. This is how it works:
function Foo( bar, bob ) {
this.bar = bar;
this.bob = bob;
}
Foo.prototype.calculate = function () {
// 'this' points not to the 'prototype' object
// as you could've expect, but to the objects
// created by calling Foo with the new keyword.
// This is what makes it work.
return this.bar - this.bob;
};
var foo1 = new Foo(9, 5);
var foo2 = new Foo(13, 3);
var result1 = foo1.calculate();
var result2 = foo2.calculate();
console.log(result1); //logs 4
console.log(result2); //logs 10
That's it!
To get closer to OOP in JavaScript, you might want to take a look into a Module design pattern (for instance, described here).
Based on the closure effect, this pattern allows emulating private properties in your objects.
With 'private' properties you can reference them directly by its identifier (i.e., no this keyword as in constructors).
But anyway, closures and design patterns in JS - an advanced topic. So, get familiar with basics (also explained in the book mentioned before).
In javascript this always refers to the owner object of the function. For example, if you define your function foo() in a page, then owner is the javascript object windows; or if you define the foo() on html element <body>, then the owner is the html element body; and likewise if you define the function onclick of element <a>, then the owner is the anchor.
In your case, you are assigning a property bar to the 'owner' object at the begining and trying to return the local variable bar.
Since you never defined any local varialbe bar, it is giving you as bar is undefined.
Ideally your code should have defined the variable as var bar; if you want to return the value zero.
this is like a public access modifier of objects(variables or functions), while var is the private access modifier
Example
var x = {};
x.hello = function(){
var k = 'Hello World';
this.m = 'Hello JavaScript';
}
var t = new x.hello();
console.log(t.k); //undefined
console.log(t.m); //Hello JavaScript
I am learning JS these days and I am unable to assimilate this Functional Pattern on page 52 of the book.
Functional
One weakness of the inheritance patterns we have seen so far is that we get no privacy.
All properties of an object are visible. We get no private variables and no
private methods. Sometimes that doesn’t matter, but sometimes it matters a lot. In frustration, some uninformed programmers have adopted a pattern of pretend
privacy. If they have a property that they wish to make private, they give it an odd looking name, with the hope that other users of the code will pretend that they cannot
see the odd looking members. Fortunately, we have a much better alternative in
an application of the module pattern.
We start by making a function that will produce objects. We will give it a name that
starts with a lowercase letter because it will not require the use of the new prefix. The
function contains four steps:
It creates a new object. There are lots of ways to make an object. It can make an
object literal, or it can call a constructor function with the new prefix, or it can
use the Object.beget method to make a new instance from an existing object, or
it can call any function that returns an object.
It optionally defines private instance variables and methods. These are just ordinary
vars of the function.
It augments that new object with methods. Those methods will have privileged
access to the parameters and the vars defined in the second step.
It returns that new object.
Here is a pseudocode template for a functional constructor (boldface text added for
emphasis):
var constructor = function (spec, my) {
var that, //other private instance variables;
my = my || {};
// Add shared variables and functions to my
that = a new object;
// Add privileged methods to that
return that;
}
The spec object contains all of the information that the constructor needs to make an
instance. The contents of the spec could be copied into private variables or transformed
by other functions. Or the methods can access information from spec as they
need it. (A simplification is to replace spec with a single value. This is useful when
the object being constructed does not need a whole spec object.)
Can anyone explain, what's going on there (in layman terms) and where such a pattern is useful?
Note: While the book you refer to is indeed an immensely helpful book, its quite ancient. Some of the "good" (and even "bad") parts have been replaced by even better alternatives and features in newest versions of JavaScript.
One weakness of the inheritance patterns we have seen so far is that
we get no privacy. All properties of an object are visible. We get no
private variables and no private methods.
A Javascript object has "properties", which can be other objects, or functions. Consider:
var obj = {a: 1, do: function(){console.log('done');} }
Nothing is stopping you from calling obj.a = 5, or obj.done().
But one might counter that that's not a good way of creating objects. We better have a prototype or class from which we can create new instances:
function Animal(name) {
this._name = name;
}
Animal.prototype.print = function(){console.log(this._name)};
or in more recent JavaScript versions:
class Animal {
constructor(name){
this._name = name;
}
print(){
console.log(this._name);
}
}
In frustration, some uninformed programmers have adopted a pattern of
pretend privacy. If they have a property that they wish to make
private, they give it an odd looking name, with the hope that other
users of the code will pretend that they cannot see the odd looking
members.
This is a comment on above code. When declaring JavaScript classes or functions, there is no official, standard, "fool proof AND syntactically elegant" way of keeping instance variables private. That is, an easy, clean way of declaring a variable that is only accessible to methods defined in that class or prototype (See this answer). So, people follow some agreed upon patterns, one of which is prefixing the variables names with a _. This actually provides no privacy to internal variables of a class instance.
With advent of the module system, one could write JavaScript code in a separate file/container and choose to make only specific objects visible to the outside world. A CommonJS example:
Animal.js:
const props = new WeakMap();
class Animal {
constructor(name){
props.set(this,{});
props.get(this).name = name;
}
set age(n){
props.get(this).age = age;
}
function print(){
console.log(props.get(this));
}
}
module.exports = Animal;
Above is one of the ways to declare a class with private properties not accessible from outside unless intentionally leaked. Notice how the object props is not exported to outside world.
Fortunately, we have a much better alternative in an application of
the module pattern.
You might think that the above module code is actually what this text means, but the above implementation is a newer version using latest features. The old school way the points in text illustrate is to expose an object creator (a.k.a factory) function. Everything declared inside the creator function and outside the created object is private by design:
function createAnimal(name){
var age = 0;
var animal = {};
animal.setAge = function(a){age = a;};
animal.getName = function(){return name;};
animal.print = function(){console.log({'name':name,'age':age});};
}
Inheritance here is a call to super creator and modifying the super instance:
function createDog(name, color){
var breed = 'unknown';
var dog = createAnimal(name);
dog.setBreed = function(b){breed = b;};
}
Essentially, the idea is to hide private variables within a closure. The variables being closed over are the (not shown) "other private instance variables", and the methods that actually are closing over these variables are the (also not shown) "privileged methods".
For example, take this function:
var createBoard = function (rows, cols) {
var cells = [];
var board = {};
for (var i = 0; i < rows; i++) {
cells[i] = [];
for (var j = 0; j < cols; j++) {
cells[i][j] = { player: null };
}
}
board.play = function (row, col, player) {
if (cells[row][col].player === null) {
cells[row][col].player = player;
}
};
board.getPlayer = function (row, col) {
return cells[row][col].player;
};
return board;
};
And let's assume we call this function to create an 8x8 gameboard:
var board = createBoard(8,8);
board.play(1,2,"Player1");
console.log(board.getPlayer(1,2));
board.play(1,2,"Player2"); // Doesn't actually do anything
// Note this code has no direct access to cells[][] except via the two
// methods we defined on the board object.
In this case, we return a board object. The board internally has access to a cells array, but we don't let anyone modify this except using our two methods, play (which occupies a board space only if it was previously unoccupied) and a getPlayer method that returns the player at a given space. Cells[][] is totally hidden to the user of this code - they couldn't cheat by changing our cell array directly.
JavaScript is an object-based language based on prototypes, rather than being class-based. 1
Compare that with Object-Oriented languages based on classes like PHP, Java, etc. In those languages, a class can be defined and member variables can have various visibility inside and outside the class. For instance, PHP has visibility set on three levels: public, protected or private.
Class members declared public can be accessed everywhere. Members declared protected can be accessed only within the class itself and by inherited classes. Members declared as private may only be accessed by the class that defines the member.2
class MyClass {
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello() {
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
But in JavaScript, we don't really have such a concept of private variables (in the same sense). That is what the author is talking about when describing the module pattern.
So if we wanted to make an analagous construct in Javascript, we could make something like this:
var MyClass = function (rows, cols) {
//this could be used in prototype functions
var private = 'Private';
var members = {
public: 'Public';
getHello: function() {
return 'MyClass _ ' + private;
}
};
return members;
};
I've heard that one of the advantages of closures is the ability to create private properties for objects as follows.
function Func2(){
//A is a closure, kept alive after the Func2 has returned,
//After Func2 returns, A is only accessible by getA and setA (it's "private")
var A = 100;
return {
getA: function(){
return A;
},
setA: function(newA){
A = newA;
}
}
}
You can get and set the private property A of an object created with Func2 using the getter and setter functions...
var obj2 = Func2();
obj2.getA();
obj2.setA(200);
But what's the point of that if I can do the same thing using a regular constructor function?
function Func1(){
var A = 100; //A is a private property of any object created with the Func1 constructor
this.getA = function(){
return A;
};
this.setA = function(newA){
A = newA;
};
}
Accessing the private properties is done the same way...
var obj1 = new Func1()
obj1.getA();
obj1.setA(200);
As others have pointed out in the comments, a closure is created in both cases, and both will work.
I think the reason that the return approach is recommended for the module pattern is that the module pattern does not make use of Javascript's prototype chain, so it's unnecessary to use a regular constructor function that would create a new prototype (which isn't needed and would waste memory). In your example, objects created by Func2 would just have the default prototype of Object.prototype, whereas objects created by Func1 would have a prototype of Func1.prototype which in turn would have the prototype Object.prototype. Also, Func2 has the advantage that it will work with or without the new keyword (although it's best to avoid the new keyword if you're using the module pattern for the reasons I mentioned above). (I have seen some programmers complain about the fact that if a programmer forgets the new keyword in traditional OO Javascript, it can cause hard-to-detect bugs; I personally have never found this to be an issue though).
Another approach to private variables, as you're probably aware, is to simply prefix them with _, e.g.:
function Func1() {
this._A = 100;
}
Func1.prototype = {
constructor: Func1,
getA: function(){
return this._A;
},
setA: function(newA){
this._A = newA;
}
};
Personally I prefer this over the module pattern - the main goal of private variables is communication to other programmers, i.e. "this is an internal property; don't access it directly" - and the underscore prefix is a well-known convention. Private properties have never really been about 100% preventing access to those properties, just discouraging it (consider the fact that most programming languages allow you to access private properties using reflection if you really want to). And also, simply prefixing with an underscore allows you to easily have "protected" properties in addition to private ones (useful for sub-types / sub-classes). Making use of the prototype chain is also more memory-efficient, because you don't have multiple copies of the same functions for each instance.
But I do realize that in spite of the simplicity of the underscore naming convention, some programmers still prefer using the module pattern to really make private properties inaccessible from outside the closure. If you want to do that, then I'd recommend using the traditional module pattern, using the return statement as in your first example.
Another pattern you could consider, if you prefer to stick with the module pattern but still want to declare public properties as you go along (rather than in a return statement at the end), would be to create a new object and use that instead of this, e.g.:
function Func3(){
var obj = {};
var A = 100;
obj.getA = function(){
return A;
};
obj.setA = function(newA){
A = newA;
};
return obj;
}
(By the way, for private methods, as opposed to private data properties, the underscore prefix isn't a necessity even if you're using the prototypal approach. The code sample in this answer is an example of this.)
I'm trying to get a really solid grasp of JavaScript and I'm stumbling across a big issue for me. I'm used to working in C languages and one of the barriers I'm finding is dealing with the prototype functionality of JavaScript and when functions are declared, as it is concerned with the order of execution.
For instance, take the following code:
var construct = new Constructor(); //I can do this even if its above the declaration of the object.
construct.MyPrivilagedFunction(); //Can do this here too, even though it's above the function declaration.
construct.MyPublicFunction(); //Can't do this because it is above the function declaration.
function Constructor() {
//Private member
var m_Ding = "Ding!";
//Accessible publicly and has access to private member.
this.MyPrivilagedFunction = function() {
console.log(m_Ding);
}
}
Constuctor.prototype.MyPublicFunction = function() {
//Doesn't have access to private members. This doesn't work.
console.log(m_Ding);
}
I understand that prototyping provides better performance because then a copy of the function is not stored on every instance of your object and instead every instance is referring to the same function (and I guess each new instance could be considered a whole new object type?). However, prototyping does not allow me to use a function before it is defined. Furthermore, a prototyped function doesn't have access to a private member of the object.
This is only really a problem because I am working on a project where two objects will need to use each other's functions. If I place one object earlier in the code, it won't have access to the second object because prototyped functions adhere to the order of execution (top to bottom).
Side Note: I'm also aware that my object should probably be an object literal ( like object={property:value}), but I'm still trying to get a solid grasp on scope and prototyping to attempt to deal with that for now.
if i get you well, the root of your problem is "two objects will need to use
each other's functions."
But in fact Javascript is not a typed language : define TypeA, define TypeB,
after that you can use instances : typeA and typeB objects with no issue.
var Speaker = function(name) {
this.name = name ;
};
Speaker.prototype.sayHi = function(aMate) {
amate.listenTo(this, ' Hi ' + this.mate.name ); // no type checking performed here
// so no issue even if Listener
// is not defined yet
};
var Listener = function(name) {
this.name = name;
this.knownMate = [];
};
Listener.prototype.listenTo = function (mate, words) {
this.knownMate.push(mate);
};
var aSpeaker = new Speaker('Joe');
var aListener = new Listener('Bobby');
aSpeaker.sayHi(aListener);
And by the way, you do not have private members in Javascript, only closures.
So yes, any function defined outside the scope of the 'private' member will
not be able to read/write to it.
Be advised also that, if performance is an issue, closures are slower on the
less performant js engine.
A not-so-bad solution to have 'pseudo-private' members is to define those members
as not enumerable with Object.defineProperty()
(watch here :
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty )
The order of execution is the one you write. There are only two exceptions from the rule "everything below is irrelevant": variable and function declarations are hoisted, i.e. you can use (assign to, call) them above. And beware of the difference between function declarations and function expressions.
var construct = new Constructor() //I can do this even if its above the declaration of the object.
Declaration of the constructor function you want to say.
construct.MyPrivilagedFunction(); //Can do this here too, even though it's above the function declaration.
There is no function declaration in here. The privileged method was created (with an assignment of a function expression to a property) during the execution of the constructor function (see above).
construct.MyPublicFunction(); //Can't do this because it is above the function declaration.
Again, it is no function declaration but an assignment of a function expression. And it didn't happen yet, because it is below.
This is only really a problem because I am working on a project where two objects will need to use each other's functions. If I place one object earlier in the code, it won't have access to the second object because prototyped functions adhere to the order of execution (top to bottom).
You usually don't need access to anything before you call anything. "Declare" everything at first (constructor, prototype properties), then instantiate.
What are the basic ways of defining reusable objects in Javascript? I say reusable to exclude singleton techniques, such as declaring a variable with object literal notation directly. I saw somewhere that Crockford defines four such ways in his book(s) but I would rather not have to buy a book for this short bit of information.
Here are the ways I'm familiar with:
Using this, and constructing with new (I think this is called classical?)
function Foo() {
var private = 3;
this.add = function(bar) { return private + bar; }
}
var myFoo = new Foo();
Using prototypes, which is similar
function Foo() {
var private = 3;
}
Foo.prototype.add = function(bar) { /* can't access private, correct? */ }
Returning a literal, not using this or new
function Foo() {
var private = 3;
var add = function(bar) { return private + bar; }
return {
add: add
};
}
var myFoo = Foo();
I can think of relatively minor variations on these that probably don't matter in any significant way. What styles am I missing? More importantly, what are the pros and cons of each? Is there a recommended one to stick to, or is it a matter of preference and a holy war?
Use the prototype. Returning specific objects from constructors makes them non-constructors, and assigning methods to this makes inheritance less convenient.
Returning an object literal
Pros:
If a person forgets new, they still get the object.
You can create truly private variables, since all methods of the object defined inside the constructor share its scope.
Cons:
It’s not a real constructor. Adding something to its prototype won’t change the returned objects, new or no new. new Foo() instanceof Foo would also result in false.
Using prototype
Pros:
You leave the constructor uncluttered.
This is the standard way of doing things in JavaScript, and all built-in constructors put their methods on their prototypes.
Inheritance becomes easier and more correct; you can (and should) use Object.create(ParentConstructor.prototype) instead of new ParentConstructor(), then call ParentConstructor from within Constructor. If you want to override a method, you’re able to do it on the prototype.
You can “modify” objects after they’ve already been created.
You can extend the prototypes of constructors you don’t have access to.
Cons:
It can get to be a bit too verbose, and if you want to change the function’s name, you have to change all of the functions added to the prototype, too. (Either that or define the prototype as one big object literal with a compatible property descriptor for constructor.)
They don’t share an instance-specific scope, so you can’t really have private variables.
Assigning to this.* in the constructor
Pros:
You can use closures and therefore private member variables.
Cons:
No duck typing; you can’t call a method right off of the prototype with any old object. For example, Array.prototype.slice.call(collectionLikeObject).
It's mostly a matter of preference. There's no one way to make Chicken Noodle soup, and uniform objects are the same way.
I don't use any of those 3, although they all work for their own purposes. I use a custom function called Object:deploy, and use it like this..
var a = { hey: 'hello' },
b = {}.deploy(a);
console.log(b.hey); // 'hello'
Using prototype is the best for most people because of automatic trickling.
function A() {};
A.prototype.hello = "Hey";
var a = new A();
console.log(a.hello); // 'Hey'
A.prototype.hello = "Hello";
console.log(a.hello); // 'Hello'
And contrary to popular belief, you can use private variables in prototype.
function Hello() {};
(function () {
var greeting = "Hello";
Hello.prototype.greet = function () { return greeting };
}).apply(this);
But even though that's possible, it's usually better to do..
function Hello() {};
Hello.prototype.greeting = "Hello";
Hello.prototype.greet = function () { return this.greeting };
Well the second approach (prototype) is more similar to standard classes in other languages like Python, in that you have a common "prototype" object which all instances are sharing. To compare the first and second approaches:
In approach 1, every time you call "new Foo()", you are creating a brand new object and inserting all the methods. This isn't very time or space efficient, since each Foo instance will have its own table of all the methods. You can test this by creating two Foo objects, and asking foo1.add == foo2.add (false). Approach 3 is very similar to this; I'm not sure what the semantic difference (if any) there is between approaches 1 and 3.
In approach 2, you have set up a shared prototype object containing all the methods. If you ask foo1.add == foo2.add, you get true. This is more space- and time-efficient. It also lets you add more methods to the prototype after creating instances, and they will see the new methods.
The problem with approach 2, as you say, is that you can't access the private members. But you can still add non-private members to the object itself, and access those using the prototype methods:
function Foo() {
this.private = 3;
}
Foo.prototype.add = function(bar) { return this.private + bar }
A caveat is that foo.private is visible externally.
The prototype one doesn't have a per object instance overhead only a per class overhead for the add function. This alone is the reason why I don't like the other two approaches.
Do not forget about inheritance. Some day you'll need. And for organizing inheritance the best approach is combined technic:
function Foo() {
this.array = [1, 2, 3];
this.add = function(bar) { return private + bar; }
}
Foo.prototype.add = function(bar) { }
var myFoo = new Foo();
Setting fields in constructor is useful to avoid modifying them by children objects.
Setting methods to prototype is faster then doing this every time in constructor.