Book Image

Object-Oriented JavaScript - Third Edition

By : Ved Antani, Stoyan STEFANOV
5 (1)
Book Image

Object-Oriented JavaScript - Third Edition

5 (1)
By: Ved Antani, Stoyan STEFANOV

Overview of this book

JavaScript is an object-oriented programming language that is used for website development. Web pages developed today currently follow a paradigm that has three clearly distinguishable parts: content (HTML), presentation (CSS), and behavior (JavaScript). JavaScript is one important pillar in this paradigm, and is responsible for the running of the web pages. This book will take your JavaScript skills to a new level of sophistication and get you prepared for your journey through professional web development. Updated for ES6, this book covers everything you will need to unleash the power of object-oriented programming in JavaScript while building professional web applications. The book begins with the basics of object-oriented programming in JavaScript and then gradually progresses to cover functions, objects, and prototypes, and how these concepts can be used to make your programs cleaner, more maintainable, faster, and compatible with other programs/libraries. By the end of the book, you will have learned how to incorporate object-oriented programming in your web development workflow to build professional JavaScript applications.
Table of Contents (25 chapters)
Object-Oriented JavaScript - Third Edition
Credits
About the Authors
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface
Built-in Functions
Regular Expressions

Object


Object() is a constructor that creates objects, for example:

    > var o = new Object(); 

This is the same as using the object literal:

    > var o = {}; // recommended 

You can pass anything to the constructor and it will try to guess what it is and use a more appropriate constructor. For example, passing a string to new Object() will be the same as using the new String() constructor. This is not a recommended practice (it's better to be explicit than let guesses creep in), but still possible:

    > var o = new Object('something'); 
    > o.constructor; 
    function String() { [native code] } 
    > var o = new Object(123); 
    > o.constructor; 
    function Number() { [native code] } 

All other objects, built-in or custom, inherit from Object. So the properties and methods listed in the following sections apply to all types of objects.

Members of the Object constructor

Following are the members of the Object constructor:

Property/method

Description

Object.prototype

The prototype of all objects (also an object itself). Anything you add to this prototype will be inherited by all other objects, so be careful:

    > var s = new String('noodles');   
    > Object.prototype.custom = 1;   
    1   
    > s.custom;   
    1   

The Object.prototype members

Instead of saying "members of the Objects created by the Object constructor", let's say headings "Object.prototype members". It is the same for Array.prototype and so on further in this appendix:

Property/method

Description

constructor

Points back to the constructor function used to create the object, in this case, Object:

    > Object.prototype.constructor === Object;   
    true   
    > var o = new Object();   
    > o.constructor === Object;   
    true   

toString(radix)

Returns a string representation of the object. If the object happens to be a Number object, the radix parameter defines the base of the returned number. The default radix is 10:

    > var o = {prop: 1};   
    > o.toString();   
    "[object Object]"   
    > var n = new Number(255);   
    > n.toString();   
    "255"   
    > n.toString(16);   
    "ff"   

toLocaleString()

Same as toString(), but matching the current locale. Meant to be customized by objects, such as Date(), Number(), and Array() and provide locale-specific values, such as different date formatting. In the case of Object() instances as with most other cases, it just calls toString().

In browsers, you can figure out the language using the property language (or userLanguage in IE) of the navigator BOM object:

    > navigator.language;   
    "en-US"   

valueOf()

Returns a primitive representation of this, if applicable. For example, Number objects return a primitive number and Date objects return a timestamp. If no suitable primitive makes sense, it simply returns this:

    > var o = {};   
    > typeof o.valueOf();   
    "object"   
    > o.valueOf() === o;   
    true   
    > var n = new Number(101);   
    > typeof n.valueOf();   
    "number"   
    > n.valueOf() === n;   
    false   
    > var d = new Date();   
    > typeof d.valueOf();   
    "number"   
    > d.valueOf();   
    1357840170137   

hasOwnProperty(prop)

Returns true if a property is an own property of the object, or false if it was inherited from the prototype chain. Also returns false if the property doesn't exist:

    > var o = {prop: 1};   
    > o.hasOwnProperty('prop');   
    true   
    > o.hasOwnProperty('toString');   
    false   
    > o.hasOwnProperty('fromString');   
    false   

isPrototypeOf(obj)

Returns true if an object is used as a prototype of another object. Any object from the prototype chain can be tested, not only the direct creator:

    > var s = new String('');   
    > Object.prototype.isPrototypeOf(s);   
    true   
    > String.prototype.isPrototypeOf(s);   
    true   
    > Array.prototype.isPrototypeOf(s);   
    false   

propertyIsEnumerable(prop)

Returns true if a property shows up in a for...in loop:

    > var a = [1, 2, 3];   
    > a.propertyIsEnumerable('length');   
    false   
    > a.propertyIsEnumerable(0);   
    true   

ECMAScript 5 additions to objects

In ECMAScript 3 all object properties can be changed, added, or deleted at any time, except for a few built-in properties (for example, Math.PI). In ES5 you have the ability to define properties that cannot be changed or deleted, a privilege previously reserved for built-ins. ES5 introduces the concept of property descriptors that give you tighter control over the properties you define.

Think of a property descriptor as an object that specifies the features of a property. The syntax to describe these features is a regular object literal, so property descriptors have properties and methods of their own, but let's call them attributes to avoid confusion. The attributes are:

  • value - what you get when you access the property

  • writable - can you change this property

  • enumerable - should it appear in for...in loops

  • configurable - can you delete it

  • set() - a function called any time you update the value

  • get() - called when you access the value of the property

Further there's a distinction between data descriptors (you define the properties enumerable, configurable, value, and writable) and accessor descriptors (you define enumerable, configurable, set(), and get()). If you define set() or get(), the descriptor is considered an accessor and attempting to define value or writable will raise an error.

Defining a regular old school ES3-style property:

    var person = {}; 
    person.legs = 2; 

Same using an ES5 data descriptor:

    var person = {}; 
    Object.defineProperty(person, "legs", { 
      value: 2, 
      writable: true, 
      configurable: true, 
      enumerable: true 
    }); 

The value of value if set to undefined by default, all others are false. So you need to set them to true explicitly if you want to be able to change this property later.

Or the same property using an ES5 accessor descriptor:

    var person = {}; 
    Object.defineProperty(person, "legs", { 
      set: function (v) {this.value = v;}, 
      get: function (v) {return this.value;}, 
      configurable: true, 
      enumerable: true 
    }); 
    person.legs = 2; 

As you can see property descriptors are a lot more code, so you only use them if you really want to prevent someone from mangling your property, and also you forget about backwards compatibility with ES3 browsers because, unlike additions to Array.prototype for example, you cannot "shim" this feature in old browsers.

And the power of the descriptors in action (defining a nonmalleable property):

    > var person = {}; 
    > Object.defineProperty(person, 'heads', {value: 1}); 
    > person.heads = 0; 
    0 
    > person.heads; 
    1 
    > delete person.heads; 
    false 
    > person.heads; 
    1 

The following is a list of all ES5 additions to Object:

Property/method

Description

Object.getPrototypeOf(obj)

While in ES3 you have to guess what is the prototype of a given object is using the method Object.prototype.isPrototypeOf(), in ES5 you can directly ask "Who is your prototype?"

    > Object.getPrototypeOf([]) ===    
       Array.prototype;   
    true   

Object.create(obj, descr)

Discussed in Chapter 7, Inheritance. Creates a new object, sets its prototype and defines properties of that object using property descriptors (discussed earlier):

    > var parent = {hi: 'Hello'};   
    > var o = Object.create(parent,
    { prop: {value: 1 }});   
    > o.hi;   
    "Hello"   

It even lets you create a completely blank object, something you cannot do in ES3:

    > var o = Object.create(null);   
    > typeof o.toString;   
    "undefined"   

Object.getOwnPropertyDescriptor(obj, property)

Allows you to inspect how a property was defined. You can even peek into the built-ins and see all these previously hidden attributes:

    > Object.getOwnProperty
      Descriptor (Object.prototype,
      'toString');   
    Object   
    configurable: true   
    enumerable: false   
    value: function toString() {
     [native code] }   
    writable: true   

Object.getOwnPropertyNames(obj)

Returns an array of all own property names (as strings), enumerable or not. Use Object.keys() to get only enumerable ones:

    > Object.getOwnPropertyNames(   
      Object.prototype);   
    ["constructor", "toString",
    "toLocaleString", "valueOf",
     ...   

Object.defineProperty(obj, descriptor)

Defines a property of an object using a property descriptor. See the discussion preceding this table.

Object.defineProperties(obj, descriptors)

Same as defineProperty(), but lets you define multiple properties at once:

    > var glass =    
     Object.defineProperties({}, {   
        "color": {   
          value: "transparent",   
          writable: true   
        },   
        "fullness": {   
          value: "half",   
          writable: false   
        }   
      });   
   
    > glass.fullness;   
    "half"   

Object.preventExtensions(obj)

Object.isExtensible(obj)

preventExtensions() disallows adding further properties to an object and isExtensible() checks whether you can add properties:

    > var deadline = {};   
    > Object.isExtensible(deadline);   
    true   
    > deadline.date = "yesterday";   
    "yesterday"   
    > Object.preventExtensions(
     deadline);   
    > Object.isExtensible(deadline);   
    false   
    > deadline.date = "today";   
    "today"   
    > deadline.date;   
    "today"   

Attempting to add properties to a non-extensible object is not an error, but simply doesn't work:

    > deadline.report = true;   
    > deadline.report;   
    undefined   

Object.seal(obj)

Object.isSealed(obj)

seal() does the same as preventExtensions() and additionally makes all existing properties non-configurable.

This means you can change the value of an existing property, but you cannot delete it or reconfigure it (using defineProperty() won't work). So you cannot, for example, make an enumerable property non-enumerable.

Object.freeze(obj)

Object.isFrozen(obj)

Everything that seal() does plus prevents changing the values of properties:

    > var deadline = Object.freeze(   
        {date: "yesterday"});   
    > deadline.date = "tomorrow";   
    > deadline.excuse = "lame";   
    > deadline.date;
"yesterday"
>
    deadline.excuse;
undefined
> 
    Object.isSealed(deadline);
true

Object.keys(obj)

An alternative to a for...in loop. Returns only own properties (unlike for...in). The properties need to be enumerable in order to show up (unlike Object.getOwnPropertyNames()). The return value is an array of strings.

    >Object.prototype.customProto =
     101;
    > Object.getOwnPropertyNames(

      Object.prototype);

    ["constructor", "toString", ...,
      "customProto"]

    > Object.keys(Object.prototype);

    ["customProto"]
> var o = {own: 202};
> o.customProto; 
101
> Object.keys(o);
"own"]