关于javascript 的继承
一.继承的几种方法
// 假设有一个需要继承的一个类型 Animal function Cat() {} Cat.prototype = new Animal // 添加一个属性 Cat.prototype.name = 'cat' ``` * 构造继承 ``` // 假设有一个需要继承的一个类型 Animal function Cat(name){ Animal.call(this) // 添加一个属性 this.name = name || 'cat' } ``` * 所以组合这两个东东:组合继承 ``` // 假设有一个需要继承的一个类型 Animal function Cat(name) { Animal.call(this) // 添加属性 this.name = name || 'cat' } Cat.prototype = new Animal() // 添加方法 Cat.prototype.say = function () { // TOOD } ``` * 优化内存节省一些: ``` // 假设有一个需要继承的一个类型 Animal function Cat(){ Animal.call(this) this.name = 'cat' } (function(){ // 创建一个没有实例方法的类 var Super = function () {} Super.prototype = Animal.prototype // 将实例作为子类的原型 Cat.prototype = new Super() // 添加方法 Cat.prototype.say = function () { // TOOD } })()
二.根据场景使用继承
有两个对象,格式如下,请根据后续条件补充代码
1 function Base() { 2 } 3 Base.extend = function(){ 4 }
前置条件:
var Base = require('之前的两个对象的路径') var View = Base.extend()
要满足以下条件:
1.可以继承
var MyClass = Base.extend({ getVal: function () { return 'hello world' } }, { say: function (word) { return word } }) //Base.extend 传了两个json对象 var myclass = new MyClass assert.equal(myclass.getVal(), 'hello world') //MyClass实例拥有getVal方法,说明getVal的方法是个prototype上的方法 assert.equal(MyClass.say('haha'), 'haha')//MyClass自己的方法,静态方法 assert.equal(myclass instanceof MyClass, true) assert.equal(myclass instanceof Base, true) //myclass继承Base
2.可以继承多次
it('可以extend多次', function () { var A = Base.extend({ say: function (word) { return word } }) var B = A.extend() //继承了Base.extend 的 extend 方法 var b = new B assert.equal(b.say('hello world'), 'hello world') // assert.equal(b instanceof View, false) //不是继承View,说明是在Base.extend 中重新定义了一个新类型 assert.equal(b instanceof B, true) // assert.equal(b instanceof A, true) // assert.equal(b instanceof Base, true) //继承了Base })
3.能够监听事件
it('能够监听事件', function (done) { const view = new View view.on('test', function () {//Base.extend 的 prototype 有一个方法是 on done() }) view.trigger('test')//Base.extend 的prototype有一个方法是trigger,trigger 触发 on 中绑定的对应名称的 function })
4.能够监听事件并传值
it('能够监听事件并传值', function (done) { const view = new View view.on('test', function (value) { assert.equal(value, 'hello world') done() }) view.trigger('test', 'hello world')//传值前面的没有传值可以使用arguments })
5.监听函数的this指向自己]
it('监听函数的this指向自己', function (done) { const view = new View view.on('test', function () {//on函数绑定的this是父对象View assert.equal(this, view) done() }) view.trigger('test') })
6.补充代码
根据以上分析:
- on和trigger 可以绑定到Base 的 prototype上
- Base.extend 返回一个新的类型Cur
-
新的类型Cur继承Base.extend
function Cat(){ Animal.call(this) this.name = 'cat' } (function(){ // 创建一个没有实例方法的类 var Super = function () {} Super.prototype = Animal.prototype // 将实例作为子类的原型 Cat.prototype = new Super() // 添加方法 Cat.prototype.say = function () { // TOOD } })()
- Base.extend传递的第一个对象的属性 绑定到 Cur 的 prototype 上
- Base.extend 传递的第二个对象的属性 绑定到 Cur上
- Base.extend 属于自己的属性(实现继承多次的属性extend) 绑定 到 Cur 上
完整代码
function Base(){
this.events = {}
}
Base.prototype.on = function(key,fn){
this.events[key] = fn;
}
Base.prototype.trigger = function(key)
{
var slice = [].slice
var args = slice.call(arguments,1)
this.events[key].apply(this,args);
}
Base.extend = function(prop,static)
{
var Super = this;
function Cur()
{
Super.call(this);
}
function Pile() {}
Pile.prototype = Super.prototype
Cur.prototype = new Pile();
for(var p in prop)
{
Cur.prototype[p] = prop[p];
}
for(var p in Super)
{
Cur[p] = Super[p];
}
for(var p in static)
{
Cur[p] = static[p];
}
return Cur;
}
module.exports = Base
优化下代码:
var slice = [].slice function merge(target) { //delete the first argument var srcs = slice.call(arguments, 1) srcs.forEach(function (src) { for (var key in src) { // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty if (src.hasOwnProperty(key)) { target[key] = src[key] } } }) } function Base() { this.events = {} } Base.extend = function (proto, static) { var Super = this; function Cur() { Super.call(this) } var Pile = function () {} Pile.prototype = Super.prototype Cur.prototype = new Pile() merge(Cur.prototype, proto) merge(Cur, Super,static); return Cur } merge(Base.prototype, { on: function (event, fn) { (this.events[event] = this.events[event] || []) .push(fn) }, trigger: function (event) { var args = slice.call(arguments, 1) ;(this.events[event] || []) .forEach((fn) => { fn.apply(this, args) }) } }) module.exports = Base