继承的五种方式
作用:减少代码量。
一、通过属性copy实现继承
对象的‘继承’本质是对象的拷贝,把一个对象的所有成员拷贝到另一个对象中。
代码演示:
// 第一个对象 var obj1 = {name ;'zs',age:18}; // 第二个对象 var ojb2 = { name: 'ls', age: 18, gender: '男', sayHi:function () { conselo.log('大家好' + this.name); } } // 把一个对象的属性和方法,拷贝到另一个对象中去 function extend(parent,child) { for ( var key in parent) { if (child[key] === undefined) { child[key] = parent[key]; } } } // 拷贝之前的obj1 console.log(obj1); // {name: "张三", age: 18} // 把obj2中的属性或方法拷贝到obj1中 extend(obj2,obj1); // 拷贝之后的obj1 console.log(obj1); // {name: "张三", age: 18, sex: "男", sayHi: ƒ}
二、原型继承
代码演示:学生类型、老师类型继承Person类型。
// 人的构造函数 function Person () { this.name = '名字'; this.age = 18; } Person.prototype.sayHi = function() { alert('大家好,我叫' + this.name); }; // 学生构造函数 function Student (stuId) { this.stuId = stuId; } // 老师构造函数 function Teacher (money) { this.money = money; } // 通过学生的原型让学生继承人 Student.prototype = new Person(); // 无法设置构造函数的参数 // 当设置了构造函数的prototype之后,别忘记设置constructor Student.prototype.constructor = Student; // 通过老师的原型让老师继承人 Teacher.prototype = new Person(); Teacher.prototype.constructor = Teacher; // 创建学生对象 var stu1 = new Student(10010); console.log(stu1); // 创建老师对象 var t1 = new Teacher(100); console.log(t1);
缺点:通过原型对象的属性是没有意义的,因为无法为每一个实例创建的对象传入参数。
三、借用构造函数继承
call函数:把一个函数调用给调用者,立即执行
语法:函数名.call(调用者,实参1,实参2,实参3...);
执行了函数名中的内部程序,并没有执行它的原型,所以只是克隆了函数名的属性。
function fn2 (num1,num2,num3) { console.log(num1,num2,num3); console.log(this); } fn2(1,2,3); // this→ window var obj = {name:'调用者'}; fn2.call(obj,4,5,6)
四、组合继承
// 人类 function Person (name,age,gender) { this.name = name; this.age = age; this.gender = gender; } Person.prototype.sayHi = function () { console.log('大家好'); }; // 学生类 function Student(name, age, gender, studId) { // this在这里指向调用者 stu1 var dyz = this; // 调用Person借给当前创建的学生对象 【① 借用继承 实现了继承属性】 Person.call(dyz,name, age,gender); this.studId = studId; }; // 【② 原型继承 实现了继承方法 】 Student.prototype = Person.prototype; Student.prototype.constructor = Student; // 给学生单独加上一个特有的考试方法 Student.prototype.exam = function () { console.log('学生考试'); }; //老师类 function Teacher(name, age, gender, money) { var dyz = this; this.money = money; // ① 借用继承Person中的属性 Person.call(dyz, name,age,gender); } // ② 原型继承Person原型中的方法 Teacher.prototype = Person.prototype; Teacher.prototype.constructor = Teacher; // 创建学生对象 var stu1 = new Student('张三',17,'男',10086); console.log(stu1); stu1.sayHi(); // 创建老师对象 var t1 = new Teacher('王五', 18, '男', 100); console.log(t1); // 缺点:给学生的原型上添加一个考试exam方法时,老师中也会多一个考试exam方法。 // 原因:学生原型 和 老师原型 指向同一个Person原型
五、借用和对象拷贝
function extend(parentObj, childObj) { for (var key in parentObj) { // 如果子对象中不存在这个属性或方法,则再去拷贝 if (childObj[key] === undefined) { // 把父对象中的属性或方法赋值给子对象 childObj[key] = parentObj[key] } } } // 人类 function Person(name, age, gender) { this.name = name this.age = age this.gender = gender } Person.prototype.sayHi = function () { console.log('大家好') } // 学生类 function Student(name, age, gender, studId) { // this在这里指向调用者 stu1 var dyz = this // 调用Person借给当前创建的学生对象 【① 借用继承 实现了继承属性】 Person.call(dyz, name, age, gender) this.studId = studId } // 【② 对象的拷贝 实现了继承方法 】 把人类(父对象)原型对象中方法 拷贝到 学生(子对象)类原型对象中 extend(Person.prototype, Student.prototype) // 给学生增加考试的方法 Student.prototype.exam = function () { console.log('学生考试') } //老师类 function Teacher(name, age, gender, money) { var dyz = this // this this.money = money // ① 借用继承Person中的属性 Person.call(dyz, name, age, gender) } // 【② 对象的拷贝 实现了继承方法 】 把人类(父对象)原型对象中方法 拷贝到 老师(子对象)类原型对象中 extend(Person.prototype, Teacher.prototype) // 创建学生对象 var stu1 = new Student('张三', 17, '男', 10086) // 给学生单独加上一个特有的考试方法,不会出现在老师类中 Student.prototype.exam = function () { console.log('学生考试') } console.log(stu1) // 创建老师对象 var t1 = new Teacher('王五', 18, '男', 100) console.log(t1)