《javascript语言精粹》读书笔记——第5章:继承

javascript是一门弱类型语言,从不须要类型转换。对象继承关系变得可有可无。对于一个对象来讲重要的是它能作什么,而不是它从哪里来。javascript是一门基于原型的语言,这意味着对象直接从其余对象继承。 javascript

一、伪类 java

javascript不直接让对象从其余对象继承,反而是插入了一个中间层:经过构造器函数产生对象。 json

当一个函数被建立时,Function 构造器产生的函数对象会运行相似这样的一些代码: 数组

this.prototype = {constructor : this};
新建立的函数对象被赋予了一个prototype属性。对于普通函数,这个属性没有任何做用。由于javascript没有提供一种方法去肯定那个函数是用来打算作构造器的,因此给每个函数对象都赋予了这样一个prototype属性。对于做为构造器的函数对象来讲,这个prototype属性是用来存放继承特征的地方。

 

函数做为构造器去构造新对象时,就是采用构造器调用模式去调用函数 ,也就是使用new 前缀去调用一个函数。此时的函数就至关于构造对象的一个类,固然这不是一个真正意义上的类,只是javascript为了刻意模拟面向对象系统而构造的一种语法。因此构造器函数是一个伪类。 闭包

如今咱们来实现一个new 方法来替代 new 操做符,经过这个new 方法咱们来看看到底new 操做符作了哪些操做: app

 

Function.prototype.method = function(name, fun) {
 this.prototype[name]= fun;
};


Object.create = function(pro){
 var F = function(){};
 F.prototype = o;
 return new F();
};


Function.method('new', function(){
    var that = Object.create(this.prototype);
    var other = this.apply(that, arguments);
    return (other && typeof other === 'object') || that;
});

上面例子首先给Function的原型添加一个method方法,这个方法被全部的函数对象继承(Function本身也是函数对象),用于给本身的原型添加某个方法。这个用这个函数构造出来的新对象将会共享(继承)这个方法。 函数

而后又给Object添加了一个create方法,这个方法用于建立一个新的对象,并以参数pro 做为构造函数的原型。这个新建立的对象将会共享(继承)pro的全部属性。 this

最后,咱们给Function原型添加了一个new方法,这个方法模拟了new操做符在构建新对象时所做的操做。让咱们看一个例子: spa

var Person = function (name, age ){
    this.name = name;
    this.age  = age;
};

var p = Person.new("clopopo",12);

p.name // "clopopo"

p.age // 12

 二、对象说明符 prototype

编写构造器函数时,参数用一个对象说明符来代替一大串参数

//使用一大串参数来构造对象
var myObject = make(f, l, m, c, s);

//使用对象说明符来代替一大串参数
myObject = make({
 first  : f,
 middle : m,
 last   : l,
 state  : s,
 city   : c
});

至关于把参数组织成了相似json对象的东西。优势是不须要记住参数的顺序,另外一个就是能够直接传入json对象,来生成真正的对象实例。

三、原型

基于原型的继承比基于类的继承模型在概念上要更简单:一个新对象能够继承一个旧对象的属性。利用上面Object的create方法,咱们彻底能够避免使用new这样使人迷惑的模拟类的继承方式(本质上仍是基于原型)。

首先,利用对象字面量来定义一个有用的对象:

var myMammal = {
    name : 'Herb the Mammal',
    get_name : function() {
        return this.name;
    },
    says : function(){
        return this.saying || '';
    }
}

一旦有一个想要的对象,咱们就能够利用Object的create方法(上文本身定义的)基于这个对象定制新的对象。

var myCat = Object.create(myMammal);
myCat.name = 'Henrietta';
myCat.saying = 'meow';
myCat.getName = function(){
    return this.says + ' ' + this.name + ' ' + this.says;
};

这是一种差别化继承,myCat查找属性时,若是自身存在就调用自身的属性,不然就去查找myCat链接的原型对象。

四、函数化

上文的几种继承方式有一个弱点就是没法保护隐私,就是咱们没法获得私有函数和私有变量。有一种很是不可取的方法就是被称为“假装私有”模式。就是给私有方法或变量去一个怪模怪样的名字,并但愿使用代码的用户伪装看不到这些变量,这是典型的自欺欺人啊。幸好javascript的闭包特性给咱们提供了一种叫作应用模块的模式。

var mammal = function(spec){
    var that = {};
    that.get_name = function(){
         return spec.name;
   };
   that.says = function(){
       return spec.saying || ' ';
   };
   return that;
}

var myMammal = mammal({name: 'Herb'});

再来看看原型继承

var cat = function(spec){
    spec.saying = spec.saying || '';
    var that = mammal(spec);
    that.get_name = function(){
        return that.says() + ' ' + spec.name; 
    }
    return that;
}
var myCat = cat('kitty');

函数化模式还给咱们提供了一个处理父类方法的方法。用闭包封存了调用superior方法对象的this和当时name属性对应的方法。

Object.method('superior', function(name){
    var that   = this,
        method = that[name];
    return function(){
        return method.apply(that, arguments);
    }; 
});

先看看这个方法的用法:

var coolcat = function(spec){
    var that = cat(spec),
        super_get_name = that.superior('get_name');
    
    that.get_name = function(n){
        return 'like ' + super_get_name() + ' baby';
    };
    return that;
};

super_get_name 获得的是cat对象建立时的get_name方法,根据superior方法定义知道,该方法永远都会以调用superior时的那个对象为上下文,上例中就是cat对象。因此调用super_get_name()时就是以cat为上下文,cat建立时的get_name方法为方法体。

相关文章
相关标签/搜索