Notes: YDKJS Objects

Syntax

Objects come in two forms: the declarative(literal) form and the constructed form.

var myObj = {
key: value
};
var myObj = new Object(); // Object.create(null);
myObj.key = value;

Type

There are six primary types in JS: string, number, boolean, null, undefined, object. Additionally, there are several other object subtypes, usually referred to as built-in objects as the followings: String, Number, Boolean, Object, Function, Array, Date, RegExp, and Error. Moreover, the JavaScript language automatically coerces a primary type like string to a String object.

Contents

Property

  • Data Descriptor: hold a value with three characteristics: writeable, enumerable, and configurable, which are default set to true.
var myObject = {
a: 2
};

Object.getOwnPropertyDescriptor( myObject, "a" );
// {
// value: 2,
// writable: true,
// enumerable: true,
// configurable: true
// }

1. Writable: the ability for you to change the value of a property

"use strict";

var myObject = {};

Object.defineProperty( myObject, "a", {
value: 2,
writable: false, // not writable!
configurable: true,
enumerable: true
} );

myObject.a = 3; // TypeError

2. Configurable: the ability to modify its descriptor definition; changing configurable to false is a one-way action, and cannot be undone.

// forbid to use the delete operator to remove an existing property 
Object.defineProperty( myObject, "a", {
value: 2,
writable: true,
configurable: false,
enumerable: true
} );

myObject.a; // 2
delete myObject.a;
myObject.a; // 2

3. Enumerable: controls wether a property will show up in certain object-property enumerations, such as the for….in loop.

  • Accessor Descriptor: have a either setter or getter or both, which override part of default operations of a property like [[Put]] and [[Get]]. It contains set and get characteristics of a property as well as configurable and enumerable.
var myObject = {
// define a getter for `a`
get a() {
return this._a_;
},

// define a setter for `a`
set a(val) {
this._a_ = val * 2;
}
};

Object.defineProperty(
myObject, // target
"b", // property name
{ // descriptor
// define a getter for `b`
get: function(){ return this.a * 2 },
// make sure `b` shows up as an object property
enumerable: true
	}
);

myObject.a = 1;

myObject.b; // 4
// related functions
1. propertyIsEnumerable(..)
2. Object.keys(..) returns an array of all enumerable properties
3. Object.getOwnPropertyNames(..) returns an array of all properties
  • Existence: The in operator will check to see if the property is in the object, or if it exists at any higher level of the [[Prototype]]chain object traversal. By contrast, hasOwnProperty(..) checks to see if only myObject has the property or not, and will not consult the [[Prototype]] chain.
var myObject = {
a: 2
};

("a" in myObject); // true
("b" in myObject); // false

myObject.hasOwnProperty( "a" ); // true
myObject.hasOwnProperty( "b" ); // false
  • Immutability: all of the following approaches create shallow immutability, which only affect the object and direct property characteristics as opposed to references.

1. Object constant: cannot be changed, redefined, or deleted

var myObject = {};

Object.defineProperty( myObject, "FAVORITE_NUMBER", {
value: 42,
writable: false,
configurable: false
} );

2. Prevent extensions: prevent an object from having new properties added to it.

var myObject = {
a: 2
};

Object.preventExtensions( myObject );

myObject.b = 3;
myObject.b; // undefined

3. Object.seal(): call Object.preventExtensions() and mark all its existing properties as configurable: false.

4. Object.freeze(): call Object.seal() and mark all “data accessor” properties as writable: false so that their values cannot be changed.

Method

Compared with properties, functions never belong to the object. Thinking of a function that just happens to be accessed on an object reference.

Duplicating Objects

var anotherObject = {
c: true
};

var anotherArray = [];

var myObject = {
a: 2,
b: anotherObject, // reference, not a copy!
c: anotherArray, // another reference!
};

anotherArray.push( anotherObject, myObject );
  • Shallow copy: end up with a on the new object as a copy of the value 2, but b, c, and d properties as just references to the same places as the references in the original object.
/*  ES6 has now defined Object.assign(..) for a shallow copy*/
var newObj = Object.assign( {}, myObject );

newObj.a; // 2
newObj.b === anotherObject; // true
newObj.c === anotherArray; // true
  • Deep copy:duplicate not only myObject, but anotherObject and anotherArray
/* objects which are JSON-safe (that is, can be serialized to a JSON string and then re-parsed to an object with the same structure and values) can easily be duplicated with */
var newObj = JSON.parse( JSON.stringify( someObj ) );
  • Circular duplication: Should we detect a circular reference and just break the circular traversal (leaving the deep element not fully duplicated)? Should we error out completely? Something in between?

Iteration

  • for..in loop: iterates over the lists of enumerable properties on an object (including its [[Prototype]] chain)
  • forEach(): iterate over all values in the array, and it ignores any callback return values.
  • every(): keeps going until the end or the callback returns a false value.
  • some(): keeps going until the end or the callback returns a true value.
  • for..of(ES6): iterate over the values directly instead of the array indicies.

Iterate over the values in data structures (arrays, objects, etc) using the ES6 for..of syntax, which looks for either a built-in or custom @@iterator object consisting of a next() method to advance through the data values one at a time.

var myObject = {
a: 2,
b: 3
};

Object.defineProperty( myObject, Symbol.iterator, {
enumerable: false,
writable: false,
configurable: true,
value: function() {
var o = this;
var idx = 0;
var ks = Object.keys( o );
return {
next: function() {
return {
value: o[ks[idx++]],
done: (idx > ks.length)
};
}
};
}
} );

// iterate `myObject` manually
var it = myObject[Symbol.iterator]();
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { value:undefined, done:true }

// iterate `myObject` with `for..of`
for (var v of myObject) {
console.log( v );
}
// 2
// 3
Like what you read? Give Kevin a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.