inherit
Now, we have a drag function to implement: suppose there is a div and we need to implement the drag function on it, then according to our usual way, the implementation method is as follows:
// Process oriented const mydiv = document.querySelector(".mydiv"); mydiv.onmousedown = e => { let ev = e || window.event; let x = ev.clientX - mydiv.offsetLeft; let y = ev.clientY - mydiv.offsetTop; mydiv.onmousemove = e => { let ev = e || window.event; let xx = ev.clientX; let yy = ev.clientY; mydiv.style.left = xx - x + "px"; mydiv.style.top = yy - y + "px"; } mydiv.onmouseup = function() { mydiv.onmousemove = ""; } } // object-oriented function Drag(ele) { this.ele = ele; this.downFn(); } Drag.prototype.downFn = function () { this.ele.onmousedown = e => { let ev = e || window.event; let x = ev.clientX - this.ele.offsetLeft; let y = ev.clientY - this.ele.offsetTop; this.moveFn(x, y); this.upFn(); } } Drag.prototype.moveFn = function (x, y) { this.ele.onmousemove = e => { let ev = e || window.event; this.setStyle(ev.clientX - x, ev.clientY - y); } } Drag.prototype.setStyle = function(leftNum,topNum){ this.ele.style.left = leftNum + "px"; this.ele.style.top = topNum + "px"; } Drag.prototype.upFn = function () { this.ele.onmouseup = () => { this.ele.onmousemove = ""; } } let mydiv = document.querySelector(".mydiv"); new Drag(mydiv);
At this time, we have added a new requirement. There are two div's, both of which need to implement the drag function, but one of them needs to be limited. Then we can realize this function by passing parameters, or by inheritance. The advantage of inheritance is that we don't need to change the previous code, but only need to add our own functions or rewrite.
Inherit and implement new requirements:
function Drag(ele) { this.ele = ele; this.downFn(); } Drag.prototype.downFn = function () { this.ele.onmousedown = e => { let ev = e || window.event; let x = ev.clientX - this.ele.offsetLeft; let y = ev.clientY - this.ele.offsetTop; this.moveFn(x, y); this.upFn(); } } Drag.prototype.moveFn = function (x, y) { this.ele.onmousemove = e => { let ev = e || window.event; this.setStyle(ev.clientX - x, ev.clientY - y); } } Drag.prototype.setStyle = function(leftNum,topNum){ this.ele.style.left = leftNum + "px"; this.ele.style.top = topNum + "px"; } Drag.prototype.upFn = function () { this.ele.onmouseup = () => { this.ele.onmousemove = ""; } } let mydiv = document.querySelector(".mydiv"); new Drag(mydiv); function LimitDrag(ele) { Drag.call(this, ele); } // Combinatorial inheritance let Link = function () { }; Link.prototype = Drag.prototype; LimitDrag.prototype = new Link(); LimitDrag.prototype.constructor = LimitDrag; // override method LimitDrag.prototype.setStyle = function (leftNum, topNum) { leftNum = leftNum < 0 ? 0 : leftNum; topNum = topNum < 0 ? 0 : topNum; this.ele.style.left = leftNum + "px"; this.ele.style.top = topNum + "px"; } let mydiv2 = document.querySelector(".mydiv2"); new LimitDrag(mydiv2);
class inheritance implementation:
class Drag { constructor(ele) { this.ele = ele; this.downFn(); } downFn() { this.ele.onmousedown = e => { let ev = e || window.event; let x = ev.clientX - this.ele.offsetLeft; let y = ev.clientY - this.ele.offsetTop; this.moveFn(x, y); this.upFn(); } } moveFn(x, y) { this.ele.onmousemove = e => { let ev = e || window.event; this.setStyle(ev.clientX - x, ev.clientY - y); } } setStyle(leftNum, topNum) { this.ele.style.left = leftNum + "px"; this.ele.style.top = topNum + "px"; } upFn() { document.onmouseup = () => { this.ele.onmousemove = ""; } } } let mydiv = document.querySelector(".mydiv"); new Drag(mydiv); class LimitDarg extends Drag { constructor(ele) { // Inheritance must be performed, a grammatical form super(ele); } setStyle(leftNum, topNum) { // override method leftNum = leftNum < 0 ? 0 : leftNum; topNum = topNum < 0 ? 0 : topNum; // Call the overridden method of the parent class super.setStyle(leftNum, topNum); } } let mydiv2 = document.querySelector(".mydiv2"); new LimitDrag(mydiv2);
Then, let's introduce several methods of inheritance:
The first is to compare the basic prototype chain inheritance, which is to achieve the purpose of inheritance by taking the instance of the parent class as the prototype of the child class.
- Prototype chain inheritance
function Dad() { this.name = "Tang San"; } function Son() {} // The subclass prototype is equal to the parent instance Son.prototype = new Dad(); let newSon = new Son(); console.log(newSon.name); // Tang San
One of the disadvantages of prototype chain inheritance is that it cannot pass parameters to the parent constructor, but it is possible to borrow constructor inheritance. It calls the parent constructor by calling call and other methods to realize inheritance.
- Borrowing constructor inheritance
function Dad(height) { this.name = "Tang San"; this.height = height; } function Son(height) { // Call the parent constructor to implement inheritance Dad.call(this, height); // Both of these methods can also be realized // Dad.apply(this,[height]) // Dad.bind(this)(height); } let newSon = new Son("178cm"); console.log(newSon.height); // 178cm console.log(newSon.name); // Tang San
However, in the borrowing constructor inheritance method, the prototype of the parent class cannot be inherited. The following code will report an error.
function Dad(height) { this.name = "Tang San"; this.height = height; } Dad.prototype.hobby = function() { console.log("golf"); } function Son(height) { Dad.call(this, height); } let newSon = new Son("178cm"); newSon.hobby(); // report errors
Then we can imagine whether assigning the prototype of the parent class to the prototype of the child class can inherit the prototype of the parent class. The following results show that son prototype = Dad. Prototype can inherit the prototype of the parent class, but there are also problems. The methods of rewriting the parent class will affect each other and modify the methods of the parent class.
function Dad(height) { this.name = "Tang San"; this.height = height; } Dad.prototype.hobby = function() { console.log("golf"); } function Son(height) { Dad.call(this, height); } Son.prototype = Dad.prototype; Son.prototype.hobby = function() { console.log("Basketball"); } let newSon = new Son("178cm"); newSon.hobby(); // Basketball let newDad = new Dad("179cm"); newDad.hobby(); // Basketball
Then we can make the child class prototype equal to the parent class instance. In this way, we will inherit not only the prototype of the parent class, but also the properties of the parent class. Combining prototype chain inheritance with borrowing constructor inheritance is combinatorial inheritance.
- Combinatorial inheritance
function Dad(height) { this.name = "Tang San"; this.height = height; } Dad.prototype.hobby = function() { console.log("golf"); } function Son(height) { Dad.call(this, height); } Son.prototype = new Dad() // However, there is a predefined attribute constructor in the prototype, so we also need to set its constructor to point to itself Son.prototype.constructor = Son; Son.prototype.hobby = function() { console.log("Basketball"); } let newSon = new Son("178cm"); newSon.hobby(); // Basketball let newDad = new Dad("179cm"); newDad.hobby(); // golf
Then we create a new constructor as a medium to cut off the relationship between the subclass prototype and the parent prototype. In this way, the prototype methods will not affect each other.
function Dad(height) { this.name = "Tang San"; this.height = height; } Dad.prototype.hobby = function() { console.log("golf"); } function Son(height) { Dad.call(this, height); } // Or use es6 to add son prototype = Object. Create (dad. Prototype) can still achieve the same effect let Link = function(){}; Link.prototype = Dad.prototype; Son.prototype = new Link(); Son.prototype.constructor = Son; Son.prototype.hobby = function() { console.log("Basketball"); } let newSon = new Son("178cm"); newSon.hobby(); // Basketball let newDad = new Dad("179cm"); newDad.hobby(); // golf
We can also use the prototype of deep copy parent class to achieve this goal.
function deepCopy(obj) { let newObj = Array.isArray(obj) ? [] : {}; for (let i in obj) { if (obj.hasOwnProperty(i)) { if (typeof obj[i] === "object") { if (obj[i] === null) { newObj[i] = null; } else { newObj[i] = deepCopy(obj[i]); } } else { newObj[i] = obj[i]; } } } return newObj; } function Dad(height) { this.name = "Tang San"; this.height = height; } Dad.prototype.hobby = function() { console.log("golf"); } function Son(height) { Dad.call(this, height); } // Using deep copy to inherit the prototype of the parent class Son.prototype = deepCopy(Dad.prototype) Son.prototype.constructor = Son; Son.prototype.hobby = function() { console.log("Basketball"); } let newSon = new Son("178cm"); newSon.hobby(); // Basketball let newDad = new Dad("179cm"); newDad.hobby(); // golf
- Class inheritance
class Dad { constructor(height){ this.name = "Tang San"; this.height = height; } hobby() { console.log("golf"); } } class Son extends Dad { constructor(height){ super(height); } hobby() { console.log("Basketball"); } }