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.
Let’s look at the first example first
Copy the code code as follows:
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.
Now modify the child to see if it will affect the parent.
Copy the code code as follows:
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.
Let’s look at another example
Copy the code code as follows:
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, data and language, are both 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 they can also be configured through parameters when new
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 satisfies the above two points.
Copy the code code as follows:
/**
* @param {String} className
* @param {String/Function} superCls
* @param {Function} factory
*/
function $class(name, superClass, factory) {
if (superClass === '') superClass = Object
functionclazz() {
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 placing an object type on the prototype of a parent class, be careful when subclasses modify it. In this case, all instances of subclasses that inherit from the parent class will be modified. And the bugs caused by this are very difficult to find.
A new API has been added to ES5 to implement prototypal inheritance: Object.create. You can use it to replace the self-implemented create function above, as follows
Copy the code code as follows:
var parent = {
name: 'jack',
age: 30,
isMarried: false
}
var child = Object.create(parent)
console.log(child)