The class keyword was introduced in Es6, but it’s just syntax sugar. Js is still a prototype-based language.

When it comes to inheritance, JS has only one result: objects.

An object is a dynamic property package.

Prototype chain

Each object has a private property (nonstandard properties: __proto__, which should be obtained via object.getprototypeof ()), refers to its constructor’s prototype — “its constructor’s prototype” also has its own prototype Object (__proto__), And so on until the prototype object of an object is null.

Null has no prototype. Null is the last link in the prototype chain.

Such as:

Function Child(){this.name = 'xiaoyu'} const Child = new Child() child-.__proto__ === child-.prototype // > true  Object.getPrototypeOf(child) === Child.prototype // > trueCopy the code

child.__proto__.__proto__.__proto__  // > null
Copy the code

Inheritance based on the prototype chain includes inheritance of properties and inheritance of methods (functions), where inheritance of functions is no different from inheritance of properties, and any function can be added to an object as a property of the object.

Inheritance implementation scheme

Class type inheritance

Class implements class-based inheritance

Es6 introduces a new keyword for implementing class, such as constructor, static, extends, and super.

class Person { constructor({name = 'xiaoyu', age = 18, sex = 0}){ Object.assign(this, { name, age, sex }) } } class Child extends Person { constructor(options = {}) { super(options) this.task = options.task this.canTravelAlone = false } } class Baby extends Child { constructor(options = {}) { super(options) this.food = 'neinei' } } const baby = new Baby({age: 1}) baby // > Baby {name: "xiaoyu", age: 1, sex: 0, task: } const child = new child ({task: 'study', age: Child {name: "xiaoyu", age: 10, sex: 0, task: 'study'}Copy the code

Object.create()Implement class-based inheritance

Single inheritance:

function Parent() { this.x = 0 this.y = 0 } Parent.prototype.move = function (x, y) { this.x += x this.y += y console.log('Parent moved') } function Child() { Parent.call(this) } Child.prototype = Object.create(Parent.prototype) Child.prototype.constructor = Parent console.log(Child.prototype) /* > constructor: __proto__ ƒ Parent () : Object */ var child = new child () console.log(child instanceof Parent) // > true child.move(1,1) // > Parent movedCopy the code

Multi-class mixed inheritance:

function Parent () { this.name = 'dayu' } function AnotherParent () { this.nickName = 'peppa' } function Child () { Parent.call(this) anotherparent.call (this)} Child. Prototype = object.create (parent.prototype) // Object Object.assign(child.prototype, AnotherParent.prototype) Child.prototype.constructor = Child Child.prototype.play = function () { console.log('play') } var child = new Child() console.log(child) /* > Child {name: "dayu", nickName: "peppa"} name: "dayu" nickName: "Peppa" __proto__: Parent constructor: ƒ Child() play: ƒ () __proto__: Object constructor: ƒ Parent() Object */Copy the code

Advantage: It is possible to create an Object defect without a prototype by using object.create (null) : The use of the object.create () second argument can cause serious performance problems when dealing with hundreds or thousands of Object descriptions in Object format, since each Object’s descriptor property has its own description Object.

New implements class-based inheritance

You can use New to create an instance, and construction.prototype to connect to the instance to form a prototype link

function Child(){
    this.name = 'xiaoyu'
    this.age = 18
}
var child = new Child()
Child.prototype.age = 10
Child.prototype.task = 'play'

// 自有属性
console.log(child.name) // > xiaoyu
// 访问不到原型上的 age ,属性遮蔽
console.log(child.age) // > 18
// 顺着原型链向上查找,找到了 task 属性
console.log(child.task) // > play

console.log(Child.prototype)
/* >
age: 10
task: "play"
constructor: ƒ Child()
__proto__:
	constructor: ƒ Object()
	__defineGetter__: ƒ __defineGetter__()
	__defineSetter__: ƒ __defineSetter__()
	hasOwnProperty: ƒ hasOwnProperty()
	__lookupGetter__: ƒ __lookupGetter__()
	__lookupSetter__: ƒ __lookupSetter__()
	isPrototypeOf: ƒ isPrototypeOf()
	propertyIsEnumerable: ƒ propertyIsEnumerable()
	toString: ƒ toString()
	valueOf: ƒ valueOf()
	toLocaleString: ƒ toLocaleString()
	get __proto__: ƒ __proto__()
	set __proto__: ƒ __proto__()
*/

console.log(child)
/* >
name: "xiaoyu"
age: 18
__proto__: 
	age: 10
	task: "play"
	constructor: ƒ Child()
	__proto__: 
		constructor: ƒ Object()
		__defineGetter__: ƒ __defineGetter__()
		__defineSetter__: ƒ __defineSetter__()
		hasOwnProperty: ƒ hasOwnProperty()
		__lookupGetter__: ƒ __lookupGetter__()
		__lookupSetter__: ƒ __lookupSetter__()
		isPrototypeOf: ƒ isPrototypeOf()
		propertyIsEnumerable: ƒ propertyIsEnumerable()
		toString: ƒ toString()
		valueOf: ƒ valueOf()
		toLocaleString: ƒ toLocaleString()
		get __proto__: ƒ __proto__()
		set __proto__: ƒ __proto__()
Copy the code

__proto__ === child. Prototype

Any function whose __proto__ is (window.) object.prototype, the attribute lookup on the prototype chain terminates at object.prototype.__proto__ (null), and undefined if not found.

Child — > child-. prototype — > object. prototype — > null

Pitfalls: This approach forces similar information to be generated in each object, which can bring unwanted methods to the generated object.

Object concatenation inheritance

Object. Assign implements inheritance

One object directly inherits from another by copying the properties of the source object. In JS, the properties of source objects are often called mixins. Starting with ES6, JS uses object.assign () to implement this process. Before ES6, Usually use lodash/underscore.extend() and jquery’s $.exntend() implementation.

const name = {name: 'xiaoyu'}
const age = {age: 18}
const sex = {sex: 0}
const task = {task: 'study'}
const canTravelAlone = {canTravelAlone: false}
const food = {food: 'normal'} 
const months = {months: 8}

const Person = (options) => {
    return Object.assign({}, name, age, sex, options)
}

const Child = (options) => {
    return Object.assign({}, name, age, sex, task, canTravelAlone, options)
}

const Baby = (options) => {
    return Object.assign({}, name, months, sex, food, options)
}

const baby = Baby({food: 'neinei'})
baby // > {name: "xiaoyu", months: 8, sex: 0, food: "neinei"}

const child = Child()
child // > {name: "xiaoyu", age: 18, sex: 0, task: "study", canTravelAlone: false}
Copy the code

As you can see, object composition ensures that objects inherit on demand, unlike class-based inheritance, where when you inherit a class, all properties of that class are inherited.

Object.create()Implementing patchwork inheritance

Stereotype linking can be implemented using object.create (), or mixed with concatenation inheritance.

var o = {
    a: 2,
    m: function(){
        return this.a + 1
    }
}
console.log(o.m()) // > 3
Copy the code

O — > object. prototype — > null

An Object created using a literal inherits all the properties of object. prototype:

Object.prototype /* > constructor: ƒ Object() __defineGetter__: ƒ __defineGetter__() __defineSetter__: ƒ __defineSetter__() hasOwnProperty: ƒ hasOwnProperty() __lookupGetter__: ƒ __lookupGetter__() __lookupSetter__: ƒ __lookupSetter__() isPrototypeOf: ƒ isPrototypeOf() propertyIsEnumerable: ƒ propertyIsEnumerable() toString: ƒ toString() valueOf: ƒ valueOf() toLocaleString: ƒ toLocaleString() Get __proto__: ƒ __proto__() set __proto__: ƒ __proto__() */ // p inherited from o, A var p = object.create (o) p.a = 4 console.log(p.m()) // > 5 p.__proto__.m() // > 3Copy the code

P — > a — > object. prototype — > null

Factory functions implement concatenation inheritance

Js, any function can create an object. A function is a factory function if it is neither a constructor nor a class, and if it returns an object that was not created by new.

Function createBook(params = {}) {return {title: 'I am a book' author: params. Author}} function createBook(params = {}) {return {title: 'I am a book' author: params.Copy the code

Function inheritance works by creating objects through factory functions and using concatenation inheritance by directly assigning properties.

Function createEbook(params = {}) {return {... CreateEbook (), cover: 'xx.jpg'}} createEbook() // > {title: 'xx.jpg', author: undefined, cover: 'xx.jpg'}Copy the code

Class inheritance and object combination inheritance comparison

  • Combining inheritance produces individual feature points rather than an entire class.
  • When new instances are adapted in composite inheritance, only new feature points need to be created without affecting existing feature points, and hence existing instances (to avoid base class fragility).

Performance considerations

  • Looking up attributes on the prototype chain is time-consuming and should be taken care of when performance is demanding

    Note: hasOwnProperty is the only js method that handles properties that do not traverse the stereotype chain.

  • Trying to access a nonexistent property traverses the entire stereotype chain

A point of confusion

var F = function() {}

Object.prototype.a = function() {
  console.log('a')
}

Function.prototype.b = function() {
  console.log('b')
}

var f = new F()

f.b()
Copy the code

F.b () executes with an error because B is not on f’s prototype chain. A lot of people think that you can find b in the order f -> f -> Function. But the fact is that f -> f -> Object.

f.__proto__ === F.prototype // > true f.__proto__.__proto__ === Object.prototype // > true F. __proto__. __proto__. __proto__ = = = null / / > true / / f on the prototype of a constructor, Function.prototype f.protototype.constructor.__proto__ === =. // > true Function.prototype // > true f instanceof F // > true F instanceof Function // > true f instanceof Function // > falseCopy the code

So what is Function?

Grammar:

new Function ([arg1[, arg2[, ...argN]],] functionBody)
Copy the code

Such as:

const sum = new Function('a', 'b', 'return a + b');
Copy the code

Function.prototype contains arguments, caller, length, name, displayName, and call, apply, and bind methods. A little f object can inherit these things, right?

Practice and think.