JavaScript uses prototypal inheritance by default. Although there is no concept of a class, its function can act as a constructor. The constructor combined with this and new can build a Java-like class. Therefore, JavaScript can emulate class-based inheritance by extending itself.
JavaScript, like other object-oriented languages, uses references for object types. The variable holding the object is just an address, while the basic type data is the value. When storing objects on prototypes, there can be some pitfalls.
Look at the first example first
var create = function() {
function Fn() {}
return function(parent) {
Fn.prototype = parent
return new Fn
}
} ()
var parent = {
name: 'jack',
age: 30,
isMarried: false
}
var child = create(parent)
console.log(child)
The create tool function implements a basic prototype inheritance. Each time create is called, a new object will be copied based on the parent object. All the properties of the new object come from the parent. . Here parent has three attributes, all of which are basic data types: string, number, and Boolean.
At this time, modify the child to see if it will affect the parent
child.name = 'lily'
child.age = 20,
child.isMarried = true
console.log(child)
console.log(parent)
The results are as follows
That is, modifying the child will not affect the parent.
Look at another example
var create = function() {
function Fn() {}
return function(parent) {
Fn.prototype = parent
return new Fn
}
}()
var parent = {
data: {
name: 'jack',
age: 30,
isMarried: false
},
language: ['Java']
}
var child = create(parent)
child.data.name = 'lily'
child.data.age = 20
child.data.isMarried = true
child.language.push('javascript')
console.dir(child)
console.dir(parent)
Note that the two attributes of parent here are data and language. They are reference types, one is an object and the other is an array. The child still inherits from the parent, and then the child is modified. The results are as follows
As you can see, the parent has also been modified at this time, and the name, age, etc. of the child are the same. This is something to be aware of when using prototypal inheritance.
A better way to use inheritance is:
1. Data attributes adopt class inheritance (hanging on this), so that new can also be configured through parameters
2. The method adopts prototypal inheritance, which can save memory. At the same time, overriding methods by subclasses will not affect the parent class
The following is a writing tool function that meets the above two points
/**
* @param {String} className
* @param {String/Function} superCls
* @param {Function} factory
*/
function $class(name, superClass, factory) {
if (superClass === '') superClass = Object
function clazz() {
if (typeof this.init === 'function') {
this.init.apply(this, arguments)
}
}
var p = clazz.prototype = new superCls
clazz.prototype.constructor = clazz
clazz.prototype.className = className
var supr = superCls.prototype
window[className] = clazz
factory.call(p, supr)
}
When the object type is placed on the prototype of the parent class, be careful when the subclass modifies it. In this case, all instances of subclasses inherited from the parent class will be modified. And the bugs caused by this are very difficult to find.
ES5 adds a new API to implement prototypal inheritance: Object.create. You can use it to replace the self-implemented create function above, as follows:
var parent = {
name: 'jack',
age: 30,
isMarried: false
}
var child = Object.create(parent)
console.log(child )