Home >Web Front-end >JS Tutorial >Learn JavaScript design patterns (inheritance)_javascript skills
1. Inheritance
Inheritance in JavaScript is a very complex topic, much more complex than inheritance in any other object-oriented language. In most other object-oriented languages, inheriting from a class only requires the use of a keyword. Unlike them, in order to achieve the purpose of inheriting public members in JavaScript, a series of measures need to be taken. What's more, JavaScript is one of the few languages that uses prototypal inheritance. Thanks to the flexibility of the language, you can use either standard class-based inheritance or the more subtle prototypal inheritance.
2. Why is inheritance needed?
Generally speaking, when designing classes, we hope to reduce repetitive code and try to weaken the coupling between objects. Using inheritance meets the needs of the previous design principle. With this mechanism, you can design based on existing classes and take advantage of the methods they already have, and it is easier to modify the design. Suppose you need several classes to have a toString() method that outputs the class structure in a specific way. Of course, you can copy and paste the code that defines the toString() method into each class, but if you do this, Whenever you need to change the way this method works, you will have to repeat the same modification in every class. On the other hand, if you provide a ToStringProvider class and then let those classes inherit this class, then the toString method only needs to be declared in one place.
Having one class inherit from another class may lead to strong coupling between the two, that is, one class depends on the internal implementation of the other class. We'll discuss some techniques that can help avoid this problem, including using dopant classes to provide methods for other classes.
3. Class-based inheritance
Look at the code below:
<script type="text/javascript"> function Person(name, age) { this.name = name; this.age = age; } Person.prototype.say = function () { console.log(this.name + " , " + this.age); } function Student(no) { this.no = no; } /** * Student的prototype指向Person的对象 */</span> Student.prototype = new Person(); var stu1 = new Student("0001"); stu1.name = '张三'; stu1.age = '11'; console.log(stu1.no); stu1.say(); </script>
Output result:
Zhang San, 11
You can see that Student has successfully integrated Person and has the say method of Person. The core code is actually Student.prototype = new Person();. The following is a diagram to illustrate the principle:
Point Student.prototype to new Person(), and new Person's _proto_ points to Person Prototype; this completes the entire inheritance.
But there are problems with this approach:
Problem 1: When the parent class has a reference type variable, the data is inconsistent. Next, we add a hobbies attribute to Person, whose type is an array.
<script type="text/javascript"> /** * 存在问题 * 1、无法在Student的构造方法中传递参数用于父类的构造方法 * 2、对于引用类型变量,造成数据不一致 */ function Person(name, age) { this.name = name; this.age = age; this.hobbies = [] ; } Person.prototype.say = function () { console.log(this.name + " , " + this.age +" , " +this.hobbies); } function Student(no) { this.no = no; } Student.prototype = new Person(); var stu1 = new Student("0001"); stu1.name = '张三'; stu1.age = '11'; stu1.hobbies.push("soccer"); stu1.say(); var stu2 = new Student("0002"); stu2.name = '李四'; stu2.age = '12'; stu2.hobbies.push("girl"); stu2.say(); </script>
Output result:
Zhang San, 11, soccer
Li Si , 12 , soccer,girl
It can be seen that John Doe’s hobbies should only be girl, but the above code allows all objects to share the hobbies attribute.
There is still a problem with the above inheritance method:
Question 2: In the constructor of Student, new Student("00001", "Zhang San", 12) cannot be used; to create an object and initialize name and age Attributes must be assigned stu.name, stu.age
In order to solve the above problem, modify the above code:
<script type="text/javascript"> function Person(name, age) { this.name = name; this.age = age; this.hobbies = []; } Person.prototype.say = function () { console.log(this.name + " , " + this.age +" , " + this.hobbies); } function Student(name, age, no) { /** * 使用call方法,第一个参数为上下文; * 有点类似Java中的super(name,age)的感觉 */ Person.call(this, name, age); this.no = no; } Student.prototype = new Person(); var stu1 = new Student("0001","张三",11); stu1.hobbies.push("soccer"); stu1.say(); var stu2 = new Student("0002","李四",12); stu2.hobbies.push("cangjin"); stu2.hobbies.push("basketball"); stu2.say(); </script>
Output:
0001, Zhang San, soccer
0002, Li Si, cangjin,basketball
Using Person.call(this,name,age) in the Student constructor feels like super(name,age) [the first parameter of call is the context]; and successfully resolves the reference The problem of attribute sharing is perfectly solved.
4. Inheritance based on prototype chain
<script type="text/javascript"> /** * 基于原型链的集成中都是对象 * 存在问题: * 1、对于引用类型变量,造成数据不一致 */ var Person = { name: "人", age: 0, hobbies: [], say: function () { console.log(this.name + " , " + this.age + " , " + this.hobbies); } } ; var Student = clone(Person); Student.no =""; Student.sayHello = function() { console.log(this.name +"hello ") ; } var stu1 = clone(Student); stu1.name = "zhangsan"; stu1.age = 12; stu1.hobbies.push("Java"); stu1.say(); var stu2 = clone(Student); stu2.name = "lisi"; stu2.age = 13; stu2.hobbies.push("Javascript"); stu2.say(); /** * 返回一个prototype执行obj的一个对象 * @param obj * @returns {F} */ function clone(obj) { var F = function () { }; F.prototype = obj; return new F(); } </script>
Output:
zhangsan, 12, Java
lisi, 13, Java,Javascript
It can be seen that there is also the problem of inconsistent reference attributes, and the entire operation is based on objects, which does not give people a good feeling. The principle is explained below through diagrams:
Objects continuously return a new object through a clone function, and prototype executes the incoming object. The entire inheritance process is actually _proto_ constantly pointing to form a chain, so it is called a prototype chain.
Okay, we have introduced it. Of the two integration methods of js, the best one is through class inheritance, which is relatively stable.
The above is an introduction to the relevant knowledge points about inheritance. I hope it will be helpful to everyone's learning.