JS的原型和继承
原型和原型链
- 原型对象: 构造函数都有一个prototype[原型]属性,这个属性的值就是原型对象。原型对象可以让构造函数创建的对象实例 共享它包含的属性和方法。在Safari、firefox、chrome在每个对象上都支持一个属性__proto__,它指向实例的构造函数的 原型。
- 原型链:对象的原型指向原型对象,多个原型的层层相连,形成原型链
Person是构造函数,zhangsan是构造行数Person创建的实例,Person的原型则是Person.prototype,通过打印,可以直到,它与zhangsan.__proto__相等。Person.prototype指向的对象,是Object构造函数创建的实例,所以Person.prototype.__proto__会等于Object.prototype,这样,Person构造函数的原型和Object构造函数的原型就构成了原型链//通过以下代码解释原型以及原型链 function Person(name) { this.name = name; } var zhangsan = new Person('zhangsan'); console.log(zhangsan.__proto__ === Person.prototype); console.log(Person.prototype.__proto__ === Object.prototype)
instanceof、constructor、typeof、isPrototypeOf
- instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否在要检测对象的原型链上
- constructor是每一个实例对象都拥有的属性,而这个属性也相当于是一个指针,它指向于创建当前对象的对象
- typeof 返回一个表达式的数据类型的字符串,包括number,boolean,string,object,undefined,function
- isPrototypeOf是用来判断指定对象object1是否存在于另一个对象object2的原型链中,例如:object1.isPrototypeOf(object2)
继承的几种方式以及优缺点
-
原型继承
function Parent(name) { this.name = name; this.colors = ['red', 'green', 'origin']; } function Child(params) { this.age = params.age; } Child.prototype.sayName = function() { console.log(`this.name=${this.name}`); } Parent.prototype.pushColor = function(color) { this.colors.push(color); } Child.prototype = new Parent('parent1'); var child1 = new Child({age: 20}); var child2 = new Child({age: 30}); child1.pushColor('yellow'); console.log(child1.colors); // ["red", "green", "origin", "yellow"] console.log(child2.colors); // ["red", "green", "origin", "yellow"]缺点:Parent方法执行了2次,没办法在不影响所有实例的情况下,给构造函数传递参数,如上例子,原本只想给child1的colors增加yellow,结果child2也增加了,不符合初衷
-
call改变上下文继承
function Parent(name) { this.name = name; } function Child(name) { this.age = 18; Parent.call(this, name); } Child.prototype.sayName = function() { console.log(`this.name=${this.name}`); } Parent.prototype.pushColor = function(color) { this.colors.push(color); } var child1 = new Child('child1'); console.log(child1.name); // child1 console.log(child1.pushColor()); // 报错 TypeError: child1.pushColor is not a function缺点:没有继承Parent原型上的方法和属性
-
组合继承
function Parent(name) { this.name = name; } function Child(params) { this.colors = ['red', 'green', 'origin']; Parent.call(this, params) } Parent.prototype.pushColor = function(color) { this.colors.push(color); } Child.prototype = new Parent('parent1'); var child1 = new Child('child1'); var child2 = new Child({age: 30}); child1.pushColor('yellow'); console.log(child1.colors); // ["red", "green", "origin", "yellow"] console.log(child2.colors); // ["red", "green", "origin"]缺点:Parent方法执行了2次
-
组合继承优化1
function Parent(name) { this.name = name; } function Child(params) { Parent.call(this, params) } Parent.prototype.sayName = function() { console.log(`this.name=${this.name}`); } Child.prototype = Object.create(Parent.prototype); var child1 = new Child('child1'); console.log(child1.name); console.log(child1.sayName());缺点: Child构造函数的constructor不是指向本身
-
组合继承优化2
function Parent(name) { this.name = name; } function Child(params) { Parent.call(this, params) } Parent.prototype.sayName = function() { console.log(`this.name=${this.name}`); } Child.prototype = Object.create(Parent.prototype); Child.prototype.constructor = Child; var child1 = new Child('child1'); console.log(child1.name); console.log(child1.sayName()); -
class继承
class Parent { static color () { return 'red' } constructor() { this.name = 'parent'; } sayName () { console.log(this.name) } } class Child extends Parent { constructor () { super(); this.age = 18; } sayAge() { console.log(this.age) } } var child1 = new Child(); console.log(child1.age); console.log(child1.sayName());