众所周知, JavaScript不是OOP(面向对象编程),但是JavaScript和面向对象语言又有一些相似之处.面向对象编程的三个基本特征:封装,继承,多态,
ES6更是直接支持了Class以及extends语法糖
原型机制是Js的一大特色,原型机制提供了创建对象的更加简单的模式(克隆模式:找到一个对象复制一个一模一样的).JavaScript实现的这个克隆方法就是Object.create(). 原型模式有以下的一些规则:
原型也是一个对象,通过这个对象实现属性方法的继承.我们可以看看prototype和__proto__这两个具体的概念.
所以个人觉得,原型的概念应该是基于函数(构造函数)来谈的,而不是实例化的对象.总结一下上面的__proto__和prototype的关系应该是: 构造函数的prototype默认将是所有这个构造函数实例化出的所有对象的原型.
functrion A () {} var a = new A() A.prototype === a.__proto__
Object.prototype.__proto__ !== Object.prototype.constructor.prototype
A.prototype === a.__proto__ // 结果为true的条件(a = new A())
a.constructor.prototype === a.__proto__ // 结果为true的条件(a = new A() && a.constructor === A)
现代浏览器都支持了Object.getPrototypeOf(o)方法,这样皆可以获取到这个对象的原型了. 函数执行过程:
每个对象都有他的原型,然后原型又有原型,经历这样一个循环往复递归的过程(终止条件就是Object.prototype, Object.prototype的原型是null)就会形成一个链状的结构,这条链状的结构就是原型链.就是通过原型链实现的继承机制
js主要是通过原型链来实现继承,但是在这个基础上,我们可以进行简单的改造来实现各种需求的不同继承方式.主要的类型有以下一些方式: 原型链 组合继承 原型继承 寄生式继承 寄生组合继承
function Parent () { this.name = 'name' } Parent.prototype.sayName = function () { console.log(this.name) } function Child () {} Child.prototype = new Parent() var child = new Child() child.sayName()
上面的即一个最简单的原型链继承的例子,子类通过将原型指向父类的一个实例化来继承父类的属性和方法,但是这个方法最大的缺点就是:子类继承的都是一个引用,任何一个子类的实例化修改了父类的属性,将导致所有子类的实例化同步的改变了.
function Parent(name) { this.name = name } Parent.prototype.sayName = function () { console.log(this.name) } function Child(name, age) { Parent.call(this, name) this.age = age } Child.prototype = new Parent() child.prototype.sayAge = function () { console.log(this.age) } var child1 = new Child('sjf', 22) var child2 = new Child('sujunfei', 20) console.log(child1.name) child1.name = 'hello' console.log(child1.name) console.log(child2.name)
上面的就是组合模式:借用构造函数和原型链继承
这样就会避免原型链和借用构造函数单独的缺点了,但是这种模式的缺点就是父类和子类都会拥有相同的属性,就是说造成属性冗余(造成原因是将Child的prototype指向Parent的实例的时候又执行了一次)
寄生组合模式
function Parent (name) { this.name = name } Parent.prototype.sayName = function () { console.log(this.name) } function Child (name) { Parent.call(this, name) } function inherits (child, parent) { var prototype = parent.prototype prototype.constructor = child child.prototype = prototype } inherits(Child, Parent) var child1 = new Child('sjf') var child2 = new Child('sujunfei') console.dir(child1)
寄生组合就是在组合的基础上把继承分类的方法的方式要更改一下,将子类的prototype指向父类的实例改成copy一份父类的prototype,让后将子类的prototype指向这个copy的副本.这样就避免了多一次调用父类否早函数造成属性的冗余.
Activity
junfeisu commentedon Aug 20, 2018
Js原型机制与继承
众所周知, JavaScript不是OOP(面向对象编程),但是JavaScript和面向对象语言又有一些相似之处.面向对象编程的三个基本特征:封装,继承,多态,
ES6更是直接支持了Class以及extends语法糖
原型机制
原型机制是Js的一大特色,原型机制提供了创建对象的更加简单的模式(克隆模式:找到一个对象复制一个一模一样的).JavaScript实现的这个克隆方法就是Object.create().
原型模式有以下的一些规则:
原型
原型也是一个对象,通过这个对象实现属性方法的继承.我们可以看看prototype和__proto__这两个具体的概念.
所以个人觉得,原型的概念应该是基于函数(构造函数)来谈的,而不是实例化的对象.总结一下上面的__proto__和prototype的关系应该是: 构造函数的prototype默认将是所有这个构造函数实例化出的所有对象的原型.
补充说明
获取原型
现代浏览器都支持了Object.getPrototypeOf(o)方法,这样皆可以获取到这个对象的原型了.
函数执行过程:
原型链
每个对象都有他的原型,然后原型又有原型,经历这样一个循环往复递归的过程(终止条件就是Object.prototype, Object.prototype的原型是null)就会形成一个链状的结构,这条链状的结构就是原型链.就是通过原型链实现的继承机制
继承
js主要是通过原型链来实现继承,但是在这个基础上,我们可以进行简单的改造来实现各种需求的不同继承方式.主要的类型有以下一些方式: 原型链 组合继承 原型继承 寄生式继承 寄生组合继承
原型链继承:
上面的即一个最简单的原型链继承的例子,子类通过将原型指向父类的一个实例化来继承父类的属性和方法,但是这个方法最大的缺点就是:子类继承的都是一个引用,任何一个子类的实例化修改了父类的属性,将导致所有子类的实例化同步的改变了.
组合继承:
上面的就是组合模式:借用构造函数和原型链继承
这样就会避免原型链和借用构造函数单独的缺点了,但是这种模式的缺点就是父类和子类都会拥有相同的属性,就是说造成属性冗余(造成原因是将Child的prototype指向Parent的实例的时候又执行了一次)
寄生组合模式
寄生组合就是在组合的基础上把继承分类的方法的方式要更改一下,将子类的prototype指向父类的实例改成copy一份父类的prototype,让后将子类的prototype指向这个copy的副本.这样就避免了多一次调用父类否早函数造成属性的冗余.