zoukankan      html  css  js  c++  java
  • javascript面向对象--自定义类型

    Javascript是基于原型实现面向对象的,因此并没有类和接口,它的对象也与其他基于类的语言中的对象有所不同。在Javascript中,每个对象都是基于一个引用类型创建的,这个引用类型可以是原生类型,也可以是自定义的类型。在没有类的情况下,可以采用下列模式创建对象。

    简单模式

    创建对象最简单的方式就是创建一个引用类型的实例,再为其添加属性和方法:

    var Person = new Object();
    
    Person.name = "Thom";
    
    Person.action = function(){
    
    };

    但是这样使用同一个接口创建很多对象,会产生大量的重复代码,不利于封装

    工厂模式

    工厂模式使用简单的函数创建对象,为对象添加属性和方法,然后返回对象。这种模式抽象了具体创建对象的过程,用函数封装并用特定接口创建对象细节。如下:

    function Person(name, age){
    
        var obj = new Object();
    
        obj.name = name;
    
        obj.age = age;
    
        obj.action = function(){};
    
        return obj;
    
    }
    
    var person1 = Person("Thom", 23);
    
    console.log(person1 instanceof Person);//false

    工厂模式可以更好的创建多个相似对象,但是却无法识别对象的类型

    构造函数模式

    通过创建自定义类型,可以想原生类型一样通过new操作符创建实例。因此,可以使用构造函数模式重写上面的例子:

    function Person(name, age){
    
        this.name = name;
    
        this.age = age;
    
        this.action = function(){};
    
    }
    
    var person1 = new Person("Thom", 23);
    
    console.log(person1 instanceof Person);//true

    注意与工厂模式的区别:

    没有显示地创建对象;

    直接将属性和方法赋给this对象;

    没有return语句;

    创建的实例为Person类型的实例。

    构造函数这种声明方式是定义在window对象中的,如果不使用new操作符,那么相当于在全局作用域中调用函数,此时this对象指向window对象,因此属性和方法将添加给window对象,可以通过window对象来调用。如下:

    Person("Alen", 33);
    
    console.log(window.name);//Alen

    然而,构造函数模式和工厂模式都有一个相同的缺点,就是每个函数都要在每个实例上重新创建一遍。由于javascript中函数也是对象,表面上每个实例似乎使用同个Function对象,实际上每个实例都自己实例化了一个Function对象。所以,构造函数的每个成员无法复用,无法在多个对象间共享方法,每个函数都要在每个实例上重新创建一遍。

    因此,不同实例间的函数是不相等的:

    function Person(name, age){
    
        this.name = name;
    
        this.age = age;
    
        this.action = function(){};
    
    }
    
    var person1 = new Person("Thom", 23);
    
    var person2 = new Person("Alen", 33);
    
    console.log(person1.action == person2.action); //false
    
    console.log(person1.name == person2.name); //false

    虽然可以通过将函数定义转移到构造函数外部(即全局作用域)来实现成员共享,但是这样定义全局函数实际上只能在构造函数中被调用。更进一步,如果对象需要定义很多方法,那么就需要定义很多全局函数,严重破坏了封装。

    function Person(name, age){
    
        this.name = name;
    
        this.age = age;
    
        this.action = action;
    
    }
    
    function action(){
    
        return this.name
    
    }
    
    var person1 = new Person("Thom", 23);
    
    var person2 = new Person("Alen", 33);
    
    console.log(person1.action == person2.action); //true

    原型模式

    原型模式可以说是解决了构造函数成员无法共享的问题,避免创建多个函数实例。但是由于它省略了构造函数传递初始化参数这一个环节,因此所有实例默认情况下都是相同属性值。。虽然共享对于函数来说非常合适,避免实例化多个函数。但是对于包含引用类型的属性,不同实例将共享同一个引用,无法拥有自己的独有属性。

    function Person(){
    
    }
    
    Person.prototype.name = new String();
    
    Person.prototype.friends = new Array();
    
    var person1 = new Person();
    
    person1.name = "Kingle";
    
    person1.friends.push("John");
    
    console.log(person1);
    
    var person2 = new Person();
    
    console.log(person2);

    用chrome console可以看到:

    clip_image002

    可以看到 person1.friends.push("John") 其实是将item添加到Person.prototype的array friends上。

    但是,person1.name = "Kingle" 却是将String赋值到person1实例的属性上。

    上面的用法就是单纯的原型模式了,而之所以会得出那样的结果是因为原型模式的共享特性。由于原型中所有属性被很多实例共享,对于基本类型值的属性倒没什么影响,因为通过在不同实例上添加同名属性,可以隐藏原型中对应属性,像上述代码中的属性name。然而,对于引用类型的属性,不同实例将会共享同一个来自prototype的引用。

    但是,实例一般有希望有自己的属性,所以很少单独使用原型模式创建对象。

    构造函数模式和原型模式的组合

    构造函数模式和原型模式各有各的优缺点,通过组合使用,构造函数模式用于定于非共享的实例属性,而原型模式用于定义方法和共享的属性,取长补短,这也是最常用的创建自定义类型的模式。如下代码:

    function Person(name, age){
    
        this.name = name;
    
        this.age = age;
    
        this.friends = ["Evan", "Jack"];
    
    }
    
    Person.prototype = {
    
        constructor : Person,
    
        action : function(){
    
            return this.name;
    
        }
    
    }
    
    var person1 = new Person("Thom", 23);
    
    person1.friends.push("Alen");
    
    var person2 = new Person("Alen", 33);
    
    console.log(person1.friends);//["Evan", "Jack", "Alen"]
    
    console.log(person2.friends);//["Evan", "Jack"]
    
    console.log(person1.action == person2.action); //true

    其他模式

    除了上面几种模式,还有一些特殊的的模式,但是基本都是基于上面几种模式的修改。

    定义自定义类型对象,再结合javascript的原型链,就可以在javascript中实现继承。

  • 相关阅读:
    Linux Shell编程(25)——I/O 重定向
    Linux Shell编程(24)——命令替换
    Linux Shell编程(23)——文本处理命令
    Linux Shell编程(22)——时间/日期 命令
    Linux Shell编程(21)——复杂命令
    玩转大数据,顺利渡过34岁裁退危机!
    传统企业IT架构如何能更好的支撑企业互联网业务的转型
    业务技术协同线上化的硬盘式研发管理实践
    做一个美女图片大全那种的网站怎么提高网站流量?
    Eclipse曾经的行业之王,为何堕落了?
  • 原文地址:https://www.cnblogs.com/Kingle/p/3151857.html
Copyright © 2011-2022 走看看