JavaScript 继承

1. 继承(inherit)

js本身是没有继承这个特性或语法的,所以js的继承比较特殊。
本质:拿来主义,原本不是自己的,但是自己可以直接用,好像就是自己的一样,这个就是继承。
因此在js中,凡是符合上述特征的都是继承(js中继承没有特定的语法)。

(1)最简单的继承就是 原型式继承
就是写一个构造函数,在原型中添加成员,那么实例对象就含有了该成员,这就称为实例对象继承自原型。

(2) 混入式继承(mix)
在js中混入就是将一个对象的成员加到另一个对象中。
典型的语法结构:
//将obj2混入到obj1中,也称obj1继承自obj2
function mix(obj1,obj2){ 
    for(var k in obj2){
        obj1[k] = obj2[k];
    }
}

一般在混入的时候,都是混入的函数,所以考虑深拷贝的机会较少,在jq框架中,有一个方法叫 extend ,该方法实现 jq 中的混入。
该方法具有的特征是:
① 将多个对象混入到一个对象中
mix ( dest, obj1, obj2, obj3, ... )
② 实现深拷贝
③ 实现原型式继承
④ 实现对象的构造(不使用构造函数创建对象)

(3)在实际开发的时候,常常是这两种方法混合使用( 混合式继承
在构造函数的原型上使用混入,那么原型对象就具有了很多方法属性等成员,那么构造函数的实例对象就自动的继承了这些成员,而且还有共享。
// 1.准备一个构造函数
function Role( name ) {
 this.name = name;
}
// 2.在原型中准备一个 extend 方法
Role.prototype.extend = function ( obj ) {
 // 将 obj 的成员混入到 原型对象中
 for ( var k in obj ) {
  this[ k ] = obj[ k ];
 }
};
// 3.尽情的扩展( 继承 )
// 为了简单这么处理
Role.skill = Role.prototype;
// 法术攻击
Role.skill.extend({
 fireBall: function () {
  console.log( '火球之术' );
 },
 bigFireBall: fucntion () ...
});
// 雷电 thunder
Role.skill.extend({
 qidoli: fucntion() { .... }
 ... 
});
// 增加技能
Role.skill.extend({
 iceSkill: fucntion() { .... }
 ... 
});
// 4.创建角色
var sasigi = new Role( 'f' );


2. 经典继承语法

在ES5出现以前,就有人模拟了继承的方式,就是使用一个对象,创建出另一个对象出来,保证被创建出来的对象的原型就是这个指定的对象。
//调用该函数,可以创建一个继承自参数给定的对象的对象
function create(baseObj){
    function F(){}
    F.prototype = baseObj;
    return new F();
}

//可以创建一个对象,该对象继承自一个数组
var myArray = create( [] );//可以将myArray作为数组使用,是真数组

/*增*/
myArray.push('第一个被push进来的数据');
myArray.unshift('第二个被unshift加入的数据');
myArray[myArray.length++]='利用数组索引加入的数据';

/*删*/
myArray.pop();//删并返回最后一个
myArray.shift();//删并返回第一个
myArray.splice(1,1);

/*改*/
myArray[1] = '哈哈哈';
myArray.splice(1,1,'a','b','c');//从下标为1开始,删掉1个元素,把后面的数据插入此位置

/*查*/
var i1 = myArray.indexOf('b');

在较新的 ES5 的规范中已经内置了该算法,使用  Object.create 来实现该功能。

所谓的简单对象,首先要保证简单,没有多余的复杂数据:
var obj = Object.create(null);
console.log(obj); //空的简单对象,里面什么都没有
没有写构造函数,obj 就是 Object 创建出来的。

var obj = Object.create(base);//此时是一种特殊情况,obj 没有构造函数,是内部创建的

3. 比较高级的继承方法

Object.create(base) => sub
该方法有两大缺点:
① 没有构造函数,无法复用
② 没有扩展,创建的子对象与父对象其实一模一样,只是层级结构不同

我们需要提供一个函数,满足以下功能:
① 可配置构造函数,由用户决定构造函数应该如何定义
② 可返回构造函数
③ 应该有继承

要求可以配置,其实就是可以自己定义属性和方法
function createClass( options ){ 
    return function(){ //这个函数就应该是最终的构造函数
    }
}

由于需要重新配置构造函数的内容与原型,也要配置方法,可以让 options 中必须带有方法数据,因此代码可以修改为另一种形式:
function createClass( options ){ 
    //要求 options中必须包含 constructor 和 methods
    //constructor是构造函数,它需要被返回
    //methods是该对象应该具有的方法,应该将方法加到原型中
    options.constructor.prototype = options.methods;
    return options.constructor;
}

简单优化后:
function createClass( options ){ 
    var ctr = options.constructor;
    ctr.prototype = options.methods;//用替换原型的办法
    return ctr;
}

使用:
属性应该放在实例对象中,方法应该放在原型中。
因此,两个参数,第一个参数用于配置实例对象的成员,第二个参数用于描述原型。
var Person = createClass({
    constructor: function(name,age,gender){
        this.name = name;
        this.age = age;
        this.gender = gender;
    },
    methods: {
        sayHello: function(){
            console.log( '你好,我是'+ this.name );
        },
        run: function(){
            console.log( '你好,'+ this.name + '在跑' );
        }
    }
});
var p = new Person('jim', 19, '男');
p.sayHello();
p.run();

此时已经有Person了,希望再派生一个Student出来
应该提供需要继承的目标(对象?函数?)
实现如下形式:



那么将需要继承的对象传入
要求options提供同一个base属性,表明需要继承谁
代码中的ctr的原型应该由base提供
function createClass( options ){ 
    var ctr = options.constructor,
        base = options.base || Object.prototype;
    ctr.prototype = Object.create(base);//如果直接把base赋给原型,会出bug,派生对象中增加的东西在原型对象中也会增加
    //方法的加入
    for(var k in options.methods){
        ctr.prototype[k] = options.methods[k];
    }
    return ctr;
}

正确的(ctr.prototype = Object.create(base);):



错误的(ctr.prototype = base;):











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值