资讯专栏INFORMATION COLUMN

javascript---类与函数化

waruqi / 3358人阅读

摘要:函数用于指定对象的行为。关于属性只在构造器函数的原型上才有的属性并指向该构造器,改写了的原型对象默认是没有属性的。函数化工厂模式在伪类模式里,构造器函数不得不重复构造器已经完成的工作。

1.对象适合于收集和管理数据,容易形成树型结构。
Javascript包括一个原型链特性,允许对象继承另一对象的属性。正确的使用它能减少对象的初始化时间和内存消耗。
2.函数它们是javascript的基础模块单元,用于代码复用、信息隐藏和组合调用。函数用于指定对象的行为。一般来说,编程就是将一组需求分解成一组函数和数据结构的技能。
3.模块我们可以使用函数和闭包来构造模块。模块是一个提供接口却隐藏实现状态和实现的函数或对象。

1.自定义类型--构造函数模式(伪类模式)

在基于类的系统中,对象是这样定义的:使用类来描述它是什么样的。假如建筑是基于类的系统,则建筑师会先画出房子的蓝图,然后房子都按照该蓝图来建造。

在使用自定义类型模式实现继承的时候,我们只需要将参数传递给构造函数,然后将参数挂载在实例对象上。其他关于实例对象的方法都不用传递参数,因为通过 实例对象调用的方法内部的this都可以访问到该参数。挂载在实例this对象上的变量称为实例变量。

组合--继承
function Person (name, age, job) {
    // 实例变量
    this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype.sayName = function () {
    alert(this.name);
}

var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
function SuperType (name) {
    this.name = name;
    this.colors = ["red","blue", "green"];
}

SuperType.prototype.sayName = function () {
    console.log(this.name);
}

function SubType (name, age) {
    // 继承属性
    SuperType.call(this,name);
    this.age = age;
}

// 继承方法
SubType.prototype = new SuperType();

SubType.prototype.sayAge = function () {
    console.log(this.age)
}

var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black")
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("Greg", 27)
console.log(instance2.colors);
instance2.sayName();
instance2.sayAge();

在继承属性和继承方法上,我们一共调用了两次超类构造函数,当通过new调用超类构造函数创建子类构造函数的原型时,有一个问题,子类构造函数的原型对象现在便是超类构造函数的实例,因此也会有在超类构造函数为实例对象this添加的属性,只是值为undefined而已,也就是说通过new调用超类构造器函数来更改子类改造器的原型时,那么在子类构造器的原型上便会有多余的属性。这便造成了浪费。而我们需要的其实只是,子类构造器的原型能够继承超类构造器原型的方法而已。因此我们需要的,1.创建一个子类构造器原型对象。2.此子类构造器原型继承自超类构造器的原型。3.因为我们在1中改写了子类构造器的原型对象,也就是重新创建了原型对象,因此我们需要在新创建的原型对象上添加constructor属性并将其赋值为子类构造器函数。
将上面的代码改写一些,如下所示。

关于constructor属性:只在构造器函数的原型上才有的属性并指向该构造器,改写了的原型对象默认是没有constructor属性的。

寄生组合式--继承
function inheritPrototype (subType,superType) {
    var prototype = Object.create(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
};

function SuperType (name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
}
function SubType(name, age) {
    //继承属性
    SuperType.call(this,name);
    this.age = age;
}
//继承方法
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function () {
    console.log(this.age);
}

var instance = new SubType();

通过隐藏那些所谓的prototype操作细节,现在看起来没那么怪异了。但是否真的有所发现:
没有私有环境,所有属性都是公开的。无法访问父类的方法。难以调试

2.原型

在一个纯粹的原型模式中,我们会摈弃类,转而专注对象。基于原型的继承相比基于类的继承在概念上更简单:一个新对象可以继承一个旧对象的属性。你通过构造有用的对象开始,接着可以构造更多和那个对象类似的对象。这就可以完全避免把一个应用拆解成一系列嵌套抽象类的分类过程

在基于原型的系统中,我们创建的对象,看起来要像我们想要的所有这种类型的对象那样,然后告诉javascript引擎,我们想要更多像这样的对象。如果建筑是基于原型的,建筑师会先建一所房子,然后将房子都建成像这种模样的。

方法Object.creat()作为new操作符的替代方案,使用它来创建javascript对象时,能增添一种更像是基于原型的感觉。

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

var myCat = Object.create(myMammal);
myCat.name = "Henrietta";
myCat.saying = "meow";
myCat.purr = function (n) {
    var i, s = "";
    for (i = 0;i < n; i += 1) {
        if(s) {
            s += "-"
        }
        s += "r";
    }
    return s;
}

myCat.get_name = function () {
    return this.says + " " + this.name + this.says;
}

这是一种"差异化继承"。通过定制一个新的对象,我们指明它与所基于的基本对象的区别。
有时候,它对某些数据结构继承于其他数据结构的情形非常有用。

3.函数化--工厂模式

在伪类模式里,构造器函数Cat不得不重复构造器Mammal已经完成的工作。在函数化模式中那不再需要了,因为构造器Cat将会调用构造器Mammal,让Mammal去做对象创建中的大部分工作,所有Cat只关注自身的差异即可。

函数化模式有很大的灵活性。它相比伪类模式不仅带来的工作更少,还让我们得到更好的封装和信息隐藏,以及访问父类方法的能力。
如果我们用函数化得样式去创建对象,并且该对象的所有方法都不用this或that,那么该对象就是持久性的。一个持久性的对象就是一个简单功能函数的集合。

私有变量:任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量。

闭包

闭包是阻止垃圾回收器将变量从内存中移除的方法,使的在创建变量的执行环境的外面能够访问到该变量。

请记住:闭包由函数创建。每次调用函数会创建一个唯一的执行环境对象。函数执行完后,执行对象就会被丢弃,除非调用者引用了它。当然,如果函数返回的是数字,就不能引用函数的执行环境对象。但是如果函数返回的是一个更复杂的结构,像是函数、对象或者数组,将返回值保存到一个变量上,就创建了一个对执行环境的引用。

Function.prototype.method = function (name,func) {
    this.prototype[name] = func;
    return this; 
}
// 工厂mammal函数
var mammal = function (spec) {
    var that = {};

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

    return that;
}

// 工厂cat函数(基于mammal的函数)
var cat = function (spec) {
    spec.saying = spec.saying || "meow";
    var that = mammal(spec);
    that.purr = function (n) {
        var i, s = "";
        for (i = 0; i < n; i += 1) {
            if(s) {
                s += "-";
            }
            s += "r";
        }
    }
    that.get_name = function () {
        return that.says() + " " + spec.name + " " + that.says();
    }
    return that;
}

// 创建myCat对象
var myCat = cat({name: "Henrietta"});

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

// 工厂coolcat函数(基于cat函数)
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;
}

var myCoolCat = coolcat({name : "Bix"});

var name = myCoolCat.get_name();

函数化模块模式有很大的灵活性。它相比构造函数模式不仅带来的工作更少,还让我们得到更好的封装休息和隐藏,以及访问父类方法的能力。如果对象的所有状态都是私有的,那么该对象就成为一个"防伪(tamper-proof)"对象。该对象的属性是可以被替换或者删除,当该对象的完整性不会受到损坏。我们用函数式的样式创建一个对象,并且该对象的所有方法都不使用this或者that,那么该对象就是持久性对象。一个持久性对象,就是一个简单的函数功能的集合。
一个持久性的对象不会被入侵。访问一个持久性的对象时,除非有方法授权,否则攻击者不会访问对象的内部状态。

模块模式

前面的模式是用于 自定义类型创建私有变量和特权方法的。而道格拉斯所说的模块模式则是为 单例创建私有变量和特权方法。所谓单例指的就是只有一个实例的对象。(就是用对象字面量表示法创建的对象)

var singleton = function () {
    // 私有变量和函数
    var privateVariable = 10;

    function privateFunction () {
        return false;
    }
    //特权/公有方法和属性
    return {
        publicProvperty: true;

        publicMethod: function () {
            privateVariable++;
            return privateFunction();
        }
    }
}

从本质上讲,这个对象字面量定义的是单例的公共接口。这种模式在需要对单例进行某些初始化,同时又需要维护其私有变量时非常有用。简言之,如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法。

增强的模块模式

这种增强的模块模式适合那些单例必须是某种类型的实例,同时还必须添加某些属性和方法对其加以增强的例子。

var singleton = function () {
    // 私有变量和函数
    var privateVariable = 10;

    function privateFunction () {
        return false
    }
    // 创建对象
    var object = new CustomType();

    // 添加特权/公有属性和方法
    object.publicProperty = true;
    object.publicMethod = function () {
        privateVariable++;
        return privateFunction();
    }

    return object;
}()

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

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

相关文章

  • TS 类与接口

    摘要:二正文中与的区别接口只声明成员方法,不做实现。在中,我们可以采用全新的基于类继承的模式设计更优雅的语义化接口,这是因为中的可以继承动态构造的类,这一点和其他的静态声明类的编程语言不同。 一 前言 1.在typescript上遇到过实例化对象的两种写法:implement和extends。extends很明显就是ES6里面的类继承,那么implement又是做什么的呢?它和extends...

    garfileo 评论0 收藏0
  • Python方法(二) - 类与继承

    摘要:在类内部的方法中使用时。类的私有方法两个下划线开头,声明该方法为私有方法,不能在类地外部调用。先在本类中查找调用的方法,找不到才去基类中找。如果在继承元组中列了一个以上的类,那么它就被称作多重继承。 类定义 类对象:创建一个类之后,可以通过类名访问、改变其属性、方法 实例对象:类实例化后,可以使用其属性,可以动态的为实例对象添加属性(类似javascript)而不影响类对象。 类...

    DevWiki 评论0 收藏0
  • JavaScript基础: 类与继承

    摘要:类的方法相当于之前我们定义在构造函数的原型上。的构造函数中调用其目的就是调用父类的构造函数。是先创建子类的实例,然后在子类实例的基础上创建父类的属性。 前言   首先欢迎大家关注我的Github博客,也算是对我的一点鼓励,毕竟写东西没法获得变现,能坚持下去也是靠的是自己的热情和大家的鼓励。    许久已经没有写东西了,因为杂七杂八的原因最近一直没有抽出时间来把写作坚持下来,感觉和跑步一...

    liuchengxu 评论0 收藏0
  • 《前端竹节》(3)【原型与对象】

    摘要:从原型对象指向构造函数画一条带箭头的线。线上标注,表示该原型对象的构造函数等于。但除此之外,若构造函数所指的显示原型对象存在于的原型链上,结果也都会为。执行构造函数,并将指针绑定到新创建的对象上。 做前端开发有段时间了,遇到过很多坎,若是要排出个先后顺序,那么JavaScript的原型与对象绝对逃不出TOP3。 如果说前端是海,JavaScript就是海里的水 一直以来都想写篇文章梳理...

    lentrue 评论0 收藏0
  • javascript类与继承

    摘要:的类与继承的类与一般的面向对象语言有很大的不同,类的标识是它的构造函数,下面先定义一个类显然我们可以看出这两个函数是不同的,虽然它们实现了相同的功能。利用构造函数来继承上面的方法子类显然无法继承父类的原型函数,这样不符合我们使用继承的目的。 javascript的类与继承 javascript的类与一般的面向对象语言有很大的不同,类的标识是它的构造函数,下面先定义一个类 var ...

    impig33 评论0 收藏0

发表评论

0条评论

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