前言
那么这篇文章是ES5的标准,所以有些内容可能会有一些,所以其它版本的标准可能会有一些不一样。
面向对象思想
面向对象编程思想:根据需求,分析对象,找到对象有什么特征和行为,通过代码方式来实现需求,要想实现这个需求,就要创建对象,要想创建对象,就应该显示有构造函数,然后通过构造函数来创建对象,通过对象调用属性和方法来实现相应的功能及需求
面向对象的三大特性:封装、继承、多态。那么这里主要说一说继承
继承的概念
继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。
举一个简单的小例子:
改变原型指向继承
// 例子:
// 人:都有姓名、年龄、性别、吃饭、睡觉、玩
// 学生:都有姓名、年龄、性别、吃饭、睡觉、玩,学习
// js中通过继承来实现
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.eat = function () {
console.log("人可以吃东西");
};
Person.prototype.sleep = function () {
console.log("人在睡觉");
};
Person.prototype.play = function () {
console.log("生活就是不一样的玩法而已")
};
// 创建学生的构造函数
function Student(score) {
this.score = score;
}
// 该表学生的原型对象的指向即可 ===》 学生和人已经发生关系了
Student.prototype = new Person("小红", 18, "女");
Student.prototype.study = function () {
console.log("学习就是一件时而枯燥无味,时而欣喜若狂的事情");
};
// 创建学生的实例对象
var stu = new Student(98);
// 冗余: 相同的代码太多,造成了代码的冗余(重复的代码)
console.log(stu.name);
console.log(stu.age);
console.log(stu.sex);
stu.play();
stu.sleep();
stu.eat();
console.log("下面的是学生对象中自己有的");
console.log(stu.score);
stu.study();
运行结果如下
可以看到,在学生的构造函数中,我们并没有传入name,sex等等的参数,但是依然可以输出,这是因为我们修改了Stuent的原型指向,使它可以获得Person中的属性和方法,这就是继承。
借用构造函数继承
-
为了让数据共享,改变原型的指向,做到了继承 – >通过原型指 向实现的继承.
缺陷:因为改变原型指向的同时实现继承,直接初始化了属性,继承过来的属性的值都是一样的,所以, 这就是问题。只能重新调用对象的属性进行重新赋值。 -
解决方法:继承的时候,不用改变原型的指向,直接调用父级的构造函数的方式来为属性赋值就可以了 — 借用构造函数:把要继
-
借用构造函数:语法:构造函数的名字.call(当前对象, 属性, 属性, 属性);
举例:
function Person(name, sex, age, weight) {
this.name = name;
this.age = age;
this.sex = sex;
this.weight = weight;
}
Person.prototype.sayHi = function () {
console.log("您好");
};
function Student(name, sex, age, weight, score) {
// 借用构造函数
Person.call(this, name, sex, age, weight);
this.score = score;
}
var stu1 = new Student("小明", "男", "14", "30kg","88");
console.log(stu1.name, stu1.sex, stu1.age, stu1.weight, stu1.score);
var stu2 = new Student("小置", "男", "16", "40kg", "67");
console.log(stu2.name, stu2.sex, stu2.age, stu2.weight, stu2.score);
var stu3 = new Student("小妮", "女", "17", "45kg", "95");
console.log(stu3.name, stu3.sex, stu3.age, stu3.weight, stu3.score);
运行结果如下:
这种方法虽然解决了属性继承,并且值不重复的问题,但是在父类中的方法却不能够继承。
组合继承
组合继承就是将原型继承和借用构造函数继承融合在一起,那么这种继承方式既可以解决属性重复的问题,又可以继承到父类中的方法。
举例
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.sayHi = function () {
console.log("阿列哈撒哟");
};
function Student(name, age, sex, score) {
// 借用构造函数,属性值重复的问题
Person.call(this, name, age, sex);
this.score = score;
}
// 改变原型的指向 -- 继承
Student.prototype = new Person(); // 不传值
Student.prototype.eat = function () {
console.log("吃东西");
};
// 构建实例对象, 属性和方法都被继承了
var stu = new Student("小黑", 20, "男", "100分");
console.log(stu.age, stu.name, stu.sex, stu.score);
stu.sayHi();
stu.eat();
运行结果如下:
拷贝继承
拷贝继承就是把父类中的元素复制一遍,个人觉得不太常用
代码如下
function Person() {
}
Person.prototype.age = 10;
Person.prototype.sex = "男";
Person.prototype.height = 100;
Person.prototype.play = function () {
console.log("玩的好开心");
};
var obj2 = {};
// Person的构造中有原型prototype,prototype就是一个对象,那么里面age,sex, height, play都是该对象的属性或方法
for (var key in Person.prototype) {
obj2[key] = Person.prototype[key];
}
console.dir(obj2);
console.log(obj2.age);
小总结
-
原型作用:数据共享,目的是:为了节省内存空间
-
原型作用:继承 目的是:为了节省内存空间
-
原型继承: 改变原型的指向
-
借用构造函数继承:主要解决属性的问题
-
组合继承: 原型继承+借用构造函数继承,既能解决属性问题,又能解决方法问题
-
拷贝继承: 就是把对象中需要共享的属性或者方法,直接遍历的方式复制到另一个对象中