资讯专栏INFORMATION COLUMN

《javascript语言精粹》学习笔记 - 继承

harriszh / 2878人阅读

摘要:但采用构造器调用模式,即是使用了前缀去调用一个函数时,函数执行的方式会改变。对象包含构造器需要构造一个新的实例的所有信息。构造器的变量和内部函数变成了该实例的私有成员。

  

JavaScript 是一门弱类型语言,从不需要类型转换。对象继承关系变得无关紧要。对于一个对象来说重要的时它能够做什么,而不是它从哪里来。

阅读《javascript语言精粹》笔记!

伪类

js的原型存在许多的矛盾,它不能直接让对象从另外一个对象继承,反而出现了一个多余的简介曾:通过构造函数来产生对象。

当函数对象创建的时候,function构造器产生的函数对象会运行类似这样的代码:

function Person() {};
Person.prototype = {
    constructor: this;
};

新的函数汇赋予一个prototype的值,因为js语言没有提供一个方法去确定哪个函数式打算来做构造器的,所以每个函数都会有一个prototype的对象。而关心的是prototype对象,而不是constructor

但采用构造器调用模式,即是使用了new前缀去调用一个函数时,函数执行的方式会改变。

Function.method("new", function(){
    var that = Object.create(this.prototype),
        other = this.apply(this, arguments);

    return (typeof other === "object" && other) || that;
});

先创建一个新的对象,它继承自构造器函数的原型对象

调用构造器函数,绑定this到新的对象上面

如果它的放回值不是一个对象的话,就放回哪个新对象

来定义两个构造器并扩展它的原型:

function Person(name) {
    this.name = name;
};  
Person.prototype.sayName = function(){
     alert(this.name);
};

function Cat(name) {
    this.name = name;
};

可以让另一个伪类去继承Person,通过定义它的constructor函数并且替换了它prototype为一个Person的实例来实现:

Cat.prototype = new Person;

然后来给Catprototype上添加一个方法:

Cat.prototype.sayHello = function(){
    alert("Hello");
};

最后实例化Cat并且调用它的方法:

var cat = new Cat("john");
cat.sayName(); // john
cat.sayHello(); // Hello

最后还有修改Catconstruction指向:

Cat.prototype.constructor = Cat;

可以通过使用method方法来定义一个inherits方法来实现伪类的继承:

Function.method("inherits", function(Parent){
    this.prototype = new Parent;
    return this;
});

伪类模式继承的问题:

没有私有环境,所有属性都是公开的。无法访问super(父类)方法。

如果在调用构造器函数时候忘记调用new操作符,那么this将不会绑定到新的对象上,而是全局window上。

“伪类”的形式可以给不收悉js的程序员便利,但它也隐藏了该语言的真实本质。借鉴类的表示法可能误导程序员去编写过于深入与复杂的层次结构。

construction的指向错误。

对象说明符

有的时候,构造器可能要接受一大串的参数,而且还要记住参数的顺序是很困难滴,在这种情况下,编写构造器的时候让它接受一个对象说明符,可能会更加的方便。

function Person(name, age, sex, scholl, add) {};

参数改成对象说明符的形式:

function Person({
    name: "john",
    age: 16,
    sex: "man",
    scholl: "zhyz",
    add:  "zhuhai"
});

好处:现在能够多个参数按照任意顺序去排列,如果构造器会聪明的使用默认值,一些参数可以被忽略掉,并且代码更加容易的阅读。

原型
  

在一个纯粹的原型继模式中,我们会摒弃类,转而专注于对象。

基于原型的继承先对基于类的继承在概念上更加简单:一个对象可以继承以旧的对象。

用对象字面量来创建一个对象:

var Person = {
    name: "john",
    sayName: function(){
        alert(this.name);
    },
    sayHello: function(){
        alert("Hello");
    }
};

有了想要的对象后,就可以利用Object.create方法来构造出更多的实例:

var nPerson = Object.create(Person);
nPerson.sayName(); // john
  

这是一种差异化继承。通过定制一个新的对象,我们指明它与所基于的基本对象的区别。

下面的例子演示了如何使用Object.create来实现类式继承。这是一个单继承。(来自MDN)

//Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}

Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
    console.info("Shape moved.");
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); //call super constructor.
}

Rectangle.prototype = Object.create(Shape.prototype);

var rect = new Rectangle();

rect instanceof Rectangle //true.
rect instanceof Shape //true.

rect.move(1, 1); //Outputs, "Shape moved."
函数化

大部分所看到的继承模式的一个弱点就是没办法去保护隐私。对象的属性都是可见的。没有办法得到私有的变量和函数。

var consturctor = function(spec, my){
    var that,   // 其他的私有实例变量
        my = my || {};

    // 把共享的变量和函数添加到 my 中
    // 给 that = 一个新的对象
    // 添加给 that 的特权方法

    // 最后把 that 对象返回
    return that;
};

创建一个对象。

定义私有实例的变量和方法。

给这个新的对象扩充方法,这些方法拥有特权去访问参数。

返回那个对象。

spec对象包含构造器需要构造一个新的实例的所有信息。spec的可能会被复制到私有变量中,或者被其他函数改变,或者方法可以在需要的时候访问spec的信息。

声明该对象私有的实例变量的方法。通过简单地声明变量就可以做到了。构造器的变量和内部函数变成了该实例的私有成员。

my对象是一个为继承链中的构构造器提供的秘密共享的容器。通过给my对象添加共享秘密成员:

my.member = value;

然后构造一个新的对象并且把它赋值给that。接着扩充that,加入组成该对象接口的特权方法。可以分配一个新函数成为that的成员方法,然后再把它分配给that

var methodical = function(){ ... };
that.methodical = methodical;

分两步去定义methodical的好处就是,如果其他方法想要调用methodical,它们可以直接调用methodical()而是不是that.methodical()。如果实例遭到破坏或修改,调用methodical照样会继续工作,因为它们私有的methodical不会该实例被修改的影响。

最后把that返回。

函数化模式有很大的灵活性。它相比伪类模式不仅带来的工作更少,还让我们得到更好的封装和信息隐藏,以及访问父类方法的能力。

如果对象的所有状态都是私有的,那么该对象就成为一个“防伪”对象。该对象的属性可以被替换或删除,但该对象的完整性不会受到伤害。

部件

从一套部件中吧对象组装出来。例如,构造一个给任何对象添加简单事件处理特性的函数。他会给对象添加一个on方法、一个fire方法和一个私有的事件注册表对象。

用这种方法,一个构造器函数可以从一套部件中把对象组装出来。js的弱类型在这里就是一个巨大的优势,因为无需花费精力去了解对象在类型系统中的集成关系。

var eventuality = function(that){
    var registry = {};

    that.fire = function(e){
        var arry, func, handler, i,
            type = typeof e === "string" ? e : e.type;

        if (registry.hasOwnProperty(type)) {
            array = registry[type];
            for (i = 0; i < array.length; i += 1) {
                handler = array[i];
                func = handler.method;
                if (typeof func === "string") {
                    func = this[func];
                }
                func.apply(this, handler.parameters || [e]);
            }
        }
        return this;
    };

    that.on = function(type, method, parameters){
        var handler = {
            method;: method,
            parameters: parameters
        };
        if (registry.hasOwnProperty(type)) {
            registry[type].push(handler);
        } else {
            registry[type] = [handler];
        }
        return that;
    };

    return that;
};

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85566.html

相关文章

  • 【阅读笔记javascript 语言精粹

    摘要:前言由于最近的项目用到了一些的代码,所以我带着好奇心,认真阅读了这本书,粗略地了解语言的基本结构和特性,对于一些不熟悉的新概念,以记录的形式加强印象,也是对学习的反思总结。 前言 由于最近的项目用到了一些js的代码,所以我带着好奇心,认真阅读了这本书,粗略地了解js语言的基本结构和特性,对于一些不熟悉的新概念,以记录的形式加强印象,也是对学习的反思总结。 一、字面量(literals...

    tangr206 评论0 收藏0
  • 读书笔记-1【javascript语言精粹继承

    摘要:使用构造器有个严重的危害,如果在调用构造器函数的时候忘记使用前缀,不仅不会绑定到新对象,还会污染全局变量原型模式原型模式中,我们采用对象来继承。 构造器调用模式 当一个函数对象被创建时,Function构造器会运行类似这样的代码: this.prototype = {constructor: this} new一个函数事会发生: Function.method(new, functio...

    malakashi 评论0 收藏0
  • JavaScript 语言精粹》读书笔记 - 函数

    摘要:语言精粹读书笔记第四章函数函数字面量函数字面量包含个部分第一部分,保留字第二部分,函数名,它可以被忽略。这个超级延迟绑定使得函数对高度复用。构造器调用模式一个函数,如果创建的目的就是希望结合的前缀来调用,那它就被称为构造器构造。 《JavaScript 语言精粹》 读书笔记 第四章 函数 Functions 函数字面量 函数字面量包含4个部分: 第一部分, 保留字 function...

    wdzgege 评论0 收藏0
  • javascript语言精粹学习笔记 - 对象

    摘要:对象适用于汇集和管理数据。一个对象字面量就是包围在一对花括号的多个名值对。尝试从对象里取值将会导致异常。亦不会触及原型链中的任何对象。严格模式下,不能用删除显式声明的标识符,名称或具名函数。 Javascirpt里的对象是无类型的。它对新属性的名字和属性的值没有任何的限制。对象适用于汇集和管理数据。对象可以包括其他对象,所以它们可以容易地表示成树状或者图形结构。 对象字面量 ...

    LoftySoul 评论0 收藏0
  • javascript语言精粹学习笔记 - 数组方法实现

    摘要:在中数组是经常被使用到的,我们除了要学习数组的方法,还需要了解诶一下某一些方法是如何来实现的。然而我看了语言精粹中方法的一章,想记录下书上的代码,以便加深印象。方法移除数组中的第一个元素并且放回该元素。 在js中数组是经常被使用到的,我们除了要学习数组的方法,还需要了解诶一下某一些方法是如何来实现的。然而我看了《javascript语言精粹》中方法的一章,想记录下书上的代码,以便加深印...

    felix0913 评论0 收藏0

发表评论

0条评论

harriszh

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<