zoukankan      html  css  js  c++  java
  • Javascript创建对象

    创建对象

    ECMAScript 定义类或对象

    使用预定义对象只是面向对象语言的能力的一部分,它真正强大之处在于能够创建自己专用的类和对象。使用 Object 构造函数或者字面量可以用来创建单个对象,但是这种行为有个明显的缺点, 创建多个对象会导致重复代码

    原始的创建对象方式

    let ferrari = new Object();
    
    ferrari.color = 'red';
    ferrari.showColor = function() {
        console.log(this.color);
    }
    

    上面的方法可以创建一个 ferrali 对象, 但是如果有多个对象将会有大量的重复代码, 比如 showColor 方法, 为了解决这个问题我们使用一种变体: 工厂模式

    工厂模式

    封装上例的方法:

    let createFerrari = function() {
        let ferrari = new Object();
    
        ferrari.color = 'red';
        ferrari.showColor = function() {
            console.log(this.color);
        }
        return ferrari;
    }
    
    let ferrari1 = createFerrari(),
        ferrari2 = createFerrari();
    

    我们使用 createFerrari() 封装上面的方法从某种程度上减少了代码量, 但创建出的对象属性值完全一样, 可以为函数传参数将其变的灵活一些

    let createFerrari = function(color) {
        let ferrari = new Object();
    
        ferrari.color = color;
        ferrari.showColor = function() {
            console.log(this.color);
        }
        return ferrari;
    }
    
    let ferrari1 = createFerrari('red'),
        ferrari2 = createFerrari('blue');
    

    上述代码每次创建对象的时候都要重新创建一个 showColor 方法, 其实我们希望这些实例能够共享一个方法

    ferrari1.showColor === ferrari2.showColor;  // false
    

    为此我们可以在工厂函数外面定义方法, 然后引入到工厂函数内部

    let showColor = function() {
        console.log(this.color);
    };
    
    let createFerrari = function(color) {
        let ferrari = new Object();
    
        ferrari.color = color;
        ferrari.showColor = showColor;
        return ferrari;
    }
    
    let ferrari1 = createFerrari('red'),
        ferrari2 = createFerrari('blue');
    
    ferrari1.showColor === ferrari2.showColor;  // true
    

    这段代码解决了创建对象时重复创建方法的问题, 但是创建实例的时候没有 new, 而且这个 showColor() 不太像是对象的方法, 它被定义到外面去了, instanceof 无法检测对象实例, 这些问题导致了 构造函数 的出现

    构造函数

    创建构造函数首先要有个名字, 大写字母开头, 并不强制, 这只是一个习惯, 用于区分其他的函数, 某种程度上 构造函数工厂函数 很类似

    let CreateFerrari = function(color) {
        this.color = color;
        this.showColor = function() {
            console.log(this.color);
        }
    }
    

    在构造函数中并没有显示创建对象, 使用 this 关键字, 创建实例的时候使用了 new 运算符, 其实在函数调用的时候其内部会创建两个特殊的对象 thisarguments, 在使用 new 运算符的时候会创建一个对象, 由 this 指向它, 默认情况构造函数会把 this return 出来, 如果指出了 return 的值情况将会有所不一样, 若 return 的是基本类型的值将无视这个 return , 还是继续将 this return, 如过 return 的是 引用类型的值将把该值返回出来, 另外 构造函数 也能在没有 new 的情况下调用, 返回值和使用 new 的时候不一样, 同样 构造函数 也是在内部定义的方法, 那么实例并没有共享该方法

    原型方式

    javascript 中的函数都有一个默认的属性 prototyoe(Function.prototype出来), prototype 可以看作创建对象索依赖的原型

    let CreateFerrari = function() {};
    
    CreateFerrari.prototype.color = 'red';
    CreateFerrari.prototype.showColor = function() {
        console.log(this.color);
    }
    
    let ferrari1 = new CreateFerrari(),
        ferrari2 = new CreateFerrari();
    

    这段代码把方法和属性定义在构造器的 prototype 上, 被 new 出来的实例都有一个指针 __proto__ 指向构造器的 prototype, 前面的问题到这里得到了一定程度的解决, 但是原型模式又暴露了新的问题, 比如构造器没有参数, 必须在对象创建后才能改变属性的默认值, 属性指向引用类型的值时将会造成问题

    let CreateFerrari = function() {};
    
    CreateFerrari.prototype.options = {
        speed: '330km/h',
        color: 'red'
    };
    CreateFerrari.prototype.showColor = function() {
        console.log(this.color);
    }
    
    let ferrari1 = new CreateFerrari(),
        ferrari2 = new CreateFerrari();
    
    ferrari1.options.price = '$3000';
    console.log(ferrari2.options.price);    // $3000
    

    混合构造函数和原型

    这种方式可像用其他程序设计语言一样创建对象。这种概念非常简单,即用构造函数定义对象的所有非共享属性,用原型方式定义对象的共享属性, 这有可保证共享属性只被创建一次, 实例可以拥有自己的属性

    let CreateFerrari = function(options) {
        this.options = options;
    };
    
    CreateFerrari.prototype.showColor = function() {
        console.log(this.color);
    };
    

    这种方式是比较完美的创建对象的方式, 是目前 ECMAScript 中使用非常广泛的一种方式, 仍有更好些的解决方案

    动态原型方式

    动态原型方法的基本想法与混合的构造函数和原型的方式相同,即在构造函数内定义非函数属性,而函数属性则利用原型属性定义, 区别是在给对象赋方法的位置

    let CreateFerrari = function(options) {
        this.options = options;
        if(typeof this.showColor !== 'function') {
            CreateFerrari.prototype.showColor = function() {
                console.log(this.color);
            }
        }
    };
    

    保证了 showColor() 只被添加一次

    其他一些另类的方式

    当上述方式无法满足需求的时候可以考虑如下方案

    寄生构造函数方式

    这种方式通常是在不能应用前一种方式时的变通方法。它的目的是创建假构造函数,只返回另一种对象的新实例。

    let CreateFerrari = function() {
        let tmp = new Object();
            tmp.color = 'red';
            tmp.showColor = function() {
                console.log(this.color);
            }
        return tmp;
    };
    
    let ferrari = new CreateFerrari();
    

    与经典构造函数不同,这种方式使用 new 运算符,使它看起来像真正的构造函数, 其实是使用了 new 运算符来调用了工厂模式, 这种模式可以在特殊的情况下用来为对象创建构造函数, 考虑如下demo

    let OtherArray = function() {
        let arr = new Array();
        arr.push(...arguments);
        arr.toMinusString = function() {
            return this.join('-');
        }
        return arr;
    };
    
    let arr = new OtherArray(1, 2, 3);
    arr.toMinusString();    //1-2-3;
    

    该方式返回的对象和构造器的原型之间没有任何联系, 也不能使用 instanceof 来检测类型, 也可以通过 es6 的 classextends 实现, 详情请见 更多信息

    稳妥构造函数

    稳妥对象是指没有公共属性, 而且其方法也不引用 this 的对象, 可以在不能使用 thisnew 的环境下使用, demo 如下:

    let Ferrari = function(color) {
        let obj = new Object();
        // 这里还能设置一些私有属性和私有方法
        obj.showColor = function() {
            console.log(color);
        }
        return obj;
    }
    let ferrari = new Ferrari('red');
        ferrari.showColor();    // red
    

    在这段代码中 ferrari 变量中保存了一个稳妥对象, 除了调用 showColor 之外再也没有办法访问到 color 变量;

    小结

    • 混合构造函数和原型 方法适合大多数创建对象的情况, 比较推荐使用
    • 动态原型方式 把所有信息封装在构造函数, 仅在必要的情况下初始化原型, 保持了同时使用构造函数和原型的优点
  • 相关阅读:
    C# ViewState
    ASP.NET C#中Application Session 的用法
    JS取 Input 控件值方法
    JS通过HTML标签自身属性获取属性值
    SQLServer 数据库操作
    查看和修改 Windows 实例远程桌面默认端口
    只能输入数字0-9 正则表达式,兼容Google Firefox IE浏览器
    C# 类初始化顺序
    window系统 任务计划程序
    微信公众号开发--消息接收与回复
  • 原文地址:https://www.cnblogs.com/idiv/p/8442084.html
Copyright © 2011-2022 走看看