js想要继承,先创建一个父类。
function Person(name,age){ this.name = name; ----属性 this.age = age; this.sayThing = function(){ ---实例方法
console.log('say something');
} }
1、原型链继承
原型链是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的。
实例对象中有__proto__,是对象,叫原型,不是标准的属性,浏览器使用,并且有的游览器不支持。
构造函数中有prototype属性,也是对象,叫原型。
注意 原型中的方法是可以互相访问的。
原型的简单语法:
1、利用原型共享数据
Person.prototype.height = '180cm';
Person.prototype.eat=function(){ console.log('吃早餐');
this.play(); }
Person.prototype.play = function(){
console.log('打球');
}
var person1 = new Person('张三',20);
2、写法二:直接这么赋值,会导致constructor构造器属性消失,需要手动修改构造器指向。
function Student(name,age,sex){ this.name=name; this.age=age; this.sex=sex; } Student.prototype={
constructor:Student, height:"188", weight:"55kg", study:function(){ console.log("好好学习i") } } var stu=new Student("小红",20,"男") console.dir(stu)
构造函数和实例对象和原型对象之间的关系
1、构造函数可以实例化对象
2、构造函数中有一个属性叫prototype,是构造函数的原型对象
3、构造函数的原型对象(prototype)中有一个constructor 构造器,这个构造器指向的就是自己所在的原型对象所在的构造函数
4、实例对象的原型对象(__proto__) 指向的是该构造函数的原型对象(prototype)
5、构造函数的原型对象(prototype)中的方法是可以被实例对象直接访问
更改原型链指向:
function Person(age) { this.age = age; } Person.prototype.eat = function () { console.log('吃萝卜'); } function Student(name) { this.name = name; } Student.prototype.play = function () { console.log('打篮球'); } Student.prototype = new Person(19); var stu = new Student('张三');
console.log('stu.age=', stu.age); --- 19 console.log('stu.name=', stu.name); ----- 张三 console.log(stu.eat); ----- function(){} console.log(stu.play); ----- undefined
原型链是可以更改指向的,定义的构造函数 Student, 更改原型链指向Person,则指向了Person的构造函数。Person的 eat 方法可以得到,此时的 play 方法 因为指向改变了,所以找不到为undefined。但是构造函数Person 和 Student 里面的独立属性是都继承的。
3、构造函数继承
// 定义一个动物类
function Animal (name) {
// 属性
this.name = name || 'Animal';
// 实例方法
this.sleep = function(){
console.log(this.name + '正在睡觉!');
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + '正在吃:' + food);
};
function Cat(name){ Animal.call(this);
Person.call(this); ------- 可以引用多个父类构造函数 this.name = name || 'Tom'; } // Test Code var cat = new Cat(); console.log(cat.name); console.log(cat.sleep()); console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // true
特点:
- 子类实例共享父类引用属性。
- 创建子类实例时,可以向父类传递参数
- 可以实现多继承(call多个父类对象)
缺点:
- 实例并不是父类的实例,只是子类的实例
- 只能继承父类的实例属性和方法,不能继承原型属性/方法
- 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
4、组合继承(组合原型链继承和借用构造函数继承)
function Person(name) { this.name = name; this.sum = function () { return 'hello'; } } function SubType(name) { Person.call(this, name) }
SubType.prototype = new Person(); var sub = new SubType('李四'); console.log('sub.name=', sub.name); --- 李四 console.log('sub.sum =', sub.sum()); ---- hello
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数Person()(耗内存),子类的构造函数会代替原型上的那个父类构造函数。