Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>JavaScript has no <s>classes</s> 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.</p> <p>A constructor is just a function that assigns properties to newly created objects. The object (created by a call with the <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/new" rel="nofollow noreferrer"><code>new</code> keyword</a>) can be referenced trough the <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this" rel="nofollow noreferrer"><code>this</code> keyword</a> (which is local to the function).</p> <p>A method also is just a function which is called <em>on</em> an object - again with <code>this</code> pointing to the object. At least when that function is invoked as a property of the object, using a <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Member_Operators" rel="nofollow noreferrer">member operator</a> (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.</p> <p>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.</p> <p>Example:</p> <pre><code>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 </code></pre> <p>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).</p> <p>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 <em>exporting locally defined functions</em> from your constructor you preserve that variable environment with local variables that can only be accessed by these functions.</p> <p>Let's see it in action:</p> <pre><code>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 </code></pre> <p>This getter function, which is defined inside the constructor, is now called a "<em>privileged</em> method" as it has access to the "private" (local) "attributes" (variables). The value of <code>bar</code> will never change. You also could declare a setter function for it, of course, and with that you might add some validation etc.</p> <p>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:</p> <pre><code>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 </code></pre> <p>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.</p> <p>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 <a href="https://stackoverflow.com/q/10898786/1048572">Correct javascript inheritance</a>, <a href="https://stackoverflow.com/q/3617139/1048572">Private variables in inherited prototypes</a>, <a href="https://stackoverflow.com/q/12463040/1048572">Define Private field Members and Inheritance in JAVASCRIPT module pattern</a> and <a href="https://stackoverflow.com/q/9248655/1048572">How to implement inheritance in JS Revealing prototype pattern?</a></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload