Thanks a lot for knowledge sharing from EnixJin, an experienced developer with ten years. The series could be split into two parts: JS core concepts(Prototype Chain & Inheritance) and module patterns(CommonJS & AMD &UMD). Here I made a summary with my ideas.
- Basic Concepts
- Details with an Example
- Conclusions
Basic Concepts
JavaScript indeed is a bit confusing for those developers experienced in OOP(object-oriented programming) languages(e.g. C++, java) . The key and hardest part is its different method for inheritance, as it is dynamic and does not provide a class
(the class
keyword is introduced in ES6(ES2015), but is syntactical sugar, JavaScript remains prototype-based).
It's important to understand the differences between these two, as they are not equivalent, and lead to much confusion down the line.
When it comes to inheritance, JavaScript only has one construct: objects. {}
- A collection of properties
- Each property has a value
- A value can be a number, string, boolean, object or function
- Only null and undefined are not objects
How to create an object in JS?
//version 1: Using an object initializer {}
// create an empty object
var emptyPerson = {};
// create an object with properties
var k = {
sex: "female",
age: 18,
getComments: function() { return "beauty"; },
"engineer": true,
occupation: {
address: "China"
}
};
//version 2: Using a constructor function (new keyword)
// create an empty object
var person = new Object();
// define an object constructor
function Person(name, age) {
this.name = name;
this.age = age;
}
// create an object
var k = new Person("Soda", 18);
//version 3: Using Object.create()
// create an empty object
var emptyPerson = Object.create(Object.prototype);
// define an object with default properties
var person = {
name: "Soda",
age: 18
}
// create an object
var k = Object.create(person);
Details with an Example
Let's take the most familiar constructor, version 2, as an example.
//version 2: Using a constructor function (new keyword)
// define an object constructor
function Person(name, age) {
this.name = name;
this.age = age;
}
// create an object
var k1 = new Person("Soda", 18); //instantiate an object, prototype inheritance was point to Person function
var k2 = new Person("Jean", 20); //instantiate another object
//case 1: adding a property for an object won't affect other instance objects.
//Explanations: This was because every instance object, a copy and prototype inherited from prototype object, is independent.
k1.region = "China";
console.log(k1.region); //The result is "China"
//Explanations: read from k1 itself property
console.log(k2.region); //The result is "undefined"
//Explanations:
//read from k2 itself properties, couldn't find it.
// try to find its prototype, Person function, couldn't find it.
// try to find function its prototype, couldn't find it.
//javascript would try to upwards lookup along the prototype chain until the prototype is null(null doesn't have prototype).
//case 2: add prototype property in prototype object would affect all instance objects.
Person.prototype.region = "Shanghai";
console.log(k1.region); //The result is "China"
//Explanations: read from k1 itself properties
console.log(k2.region); //The result is "Shanghai"
//Explanations: read from k2 itself properties, couldn't find so try to find its prototype, get it.
Conclusions
The pitfalls of prototype inheritance are usually hard to figure out, especially in large complex code structure. So far, most common cases I faced are listed above. Please be careful to modify prototype object.
All implementations are based on this prototype inheritance mechanism. From my perspective, knowing mechanism is much more important than learning implementation. If there are any questions, please feel free to write in comments. Next, we would talk about module patterns.