JS继承

继承是根据原型链实现的,一层层进行引用,当查找某个实例中的属性时,先在实例中进行查找,如果没有,再到原型中进行查找,如果原型还没有,在到prototype指向的父类模型中进行查找,像链条一样依次向上查找,直到找到该属性。

                

function Person() {

                this.age = 12;

            }

            Person.prototype.Say = function () {

                console.log("hello");

            }

            function Students() {

                this.name = "aa";

            }

            Students.prototype.Learn = function () {

                console.log("study");

            }

            Students.prototype = new Person();

 

            var student = new Students();

            student.Say(); // hello

            console.log(student.age); //12

            console.log(Students.prototype.constructor);  //function Person 实际上不是Students的原型的constructor被重写了,而是Students的原型指向了另一个对象(Person)的原型,而这个原型对象的constructor属性指向的是Person

            console.log(Students.prototype); //Person {age: 12}

我们知道,所有引用类型都继承了object,而这个继承也是通过原型链实现的,我们要记住,所有函数的默认原型都是object的实例,因此默认原型都会包含一个内部指针,指向object.prototype,这也正是所有自定义类型都会继承tostring()等默认方法的原因。

继承中使用引用类型变量的问题

function Person() {

                this.age = 12;

                this.color = ["red", "black"];

            }

            Person.prototype.Say = function () {

                console.log("hello");

            }

            function Students() {

                this.name = "aa";

            }

            Students.prototype.Learn = function () {

                console.log("study");

            }

            Students.prototype = new Person();

 

            var student = new Students();

            student.color[0] = "white";

            student.age = 55;

            console.log(student.color[0]); //white

            console.log(student.age); //55

            var student1 = new Students();

            console.log(student1.color[0]);////white

            console.log(student1.age); //12

可以看到,上面使用值类型定义的变量没有共享,而引用类型的变量产生了共享,某个实例在修改引用类型的变量时,会直接影响所有实例的值,因这显然是不科学的

解决方法:

function Person() {

                this.age = 12;

                this.color = ["red", "black"];

            }

            Person.prototype.Say = function () {

                console.log("hello");

            }

            function Students() {

                Person.call(this);

                this.name = "aa";

            }

            Students.prototype.Learn = function () {

                console.log("study");

            }

            Students.prototype = new Person();

 

            var student = new Students();

            student.color[0] = "white";

            student.age = 55;

            console.log(student.color[0]); //white

            console.log(student.age); //55

            var student1 = new Students();

            console.log(student1.color[0]);////red

            console.log(student1.age); //12

解决方法是,在子类型构造函数的内部调用超类型构造函数,这样使用apply和call方法,可以在以后新创建的对象上执行构造函数。

最理想的继承方法:

function Person() {

                this.age = 12;

                this.color = ["red", "black"];

            }

            Person.prototype.Say = function () {

                console.log("hello");

            }

            function Students() {

                Person.call(this);

                this.name = "aa";

            }

            Students.prototype.Learn = function () {

                console.log("study");

            }

            function inheritPrototype(subType, superType) {

                var prototype = Object.create(superType.prototype);

                prototype.constructor = subType;

                subType.prototype = prototype;

            }

            inheritPrototype(Students, Person);

            var student = new Students();

            var student1 = new Students();

            student.color[0] = "white";

            console.log(student.color[0]);

                      console.log(student1.color[0]);

这中法只调用了一次父类的构造函数,并且避免子类的prototype上创建不必要的属性,还能保持原型链的不变,所以这是最理想的方式。

 

 

 

 

原文地址:https://www.cnblogs.com/y8932809/p/5395193.html