前端学习指南让前端飞饥人谷技术博客

《高程第六章---面向对象程序设计》小结---创建对象(该章节重

2017-12-03  本文已影响67人  大春春

《JavaScript高级程序设计》这本书比较厚,之前刚学JS的时候挑战过一次,结果止步第三章。现在工作了一段时间想想还是得回过头来补充一下基础知识的。目前刚看完第六章,就从第六章开始总结吧,再逐步补充之前的好了。

本章小结

创建对象章节主要讲解如何解决一个问题:使用对象字面量或者Object构造函数创建对象时会因此产生的大量冗余代码。
解决该问题的思路有很多,本章介绍的有①工厂模式,②构造函数,③原型模式,④原型与构造函数的组合,⑤动态原型,⑥稳妥构造函数。
并且在介绍这些方法的同时也介绍了这些方法的试用问题和优缺点,并提出了解决方案。
该博客会采用介绍方法->提出该方法的问题->如何解决该方法产生的问题这样的步骤来进行讲解,代码的展示有可能用截图的形式

工厂模式

// 例如我们要创建多个单车对象,先创建一个生产单车的工厂
        function factory(brand, weight, height) {
            let bike = new Object()
            bike.brand = brand
            bike.weight = weight
            bike.height = height
            bike.ride = function() {
                console.log('ride')
            }
            return bike
        }
// 然后通过设定单车的参数,让工厂生产出我们所需要的单车
        let bikeA = factory('oxc', '3kg', '1.1m')
        let bikeB = factory('mmp', '2kg', '1.2m')
// 这样我们就得到了两个单车
bikeA: {brand: "oxc", weight: "3kg", height: "1.1m", ride: ƒ} 
bikeB: {brand: "mmp", weight: "2kg", height: "1.2m", ride: ƒ}
// 也可以通过无数次的调用factory函数去创建无数个你想要的型号的单车
        function factory() {
            let str = new String('oxc')
            return str
        }
        let oxc = factory()
        console.log(typeof oxc)   // object
// 当然,可以通过instanceof这个方法判定创建出来的对象是不是string类型,但是这样也会有一个问题,普通赋值方法创建出来的字符串用instanceof是无法判断该字符串是不是属于string类型的,而我们平时创建字符串时也极少使用Sting构造函数去创建一个字符串
let a = 'oxc'
a instanceof String // false

随后,又出现了使用构造函数模式创建对象的方法

构造函数模式

        function Bike(brand, weight, height) {
            this.brand = brand
            this.weight = weight
            this.height = height
            this.ride = function() {
                console.log('ride')
            }
        }
        let oxc = new Bike('oxc', '1.2kg', '1.3m') //  {brand: "oxc", weight: "1.2kg", height: "1.3m", ride: ƒ}
// 虽然该方法和工厂模式区别不大,但是还需要理解一下new操作符在这中间做了什么事情

为了解决方法重复创建的问题,后来又出现了原型模式

原型模式

        // 将属性和方法都设置到Bike函数的prototype属性中去
        function Bike() {}
        Bike.prototype.brand = 'oxc'
        Bike.prototype.weight = '1.2kg'
        Bike.prototype.height = '1.2m'
        Bike.prototype.ride = function() {
            console.log('ride')
        }
        let bikeA = new Bike()
        let bikeB = new Bike()
        bikeA.ride()                 // ride
        bikeB.ride()                 // ride
        console.log(bikeA.ride === bikeB.ride)   // true   bikeA和bikeB对象的ride方法变成了同一个
        function Bike() {}
        Bike.prototype = {
            brand: 'oxc',
            weight: '1.2kg',
            height: '1.2m',
            constructor: Bike,
            ride() {
                console.log('ride')
            }
        }
  1. 如果将引用类型放到构造函数的原型对象上去,会导致由该构造函数创建出来的实例全部共享这个引用类型(就像函数被共享了一样),比如下面这个例子:
        function A() {}
        A.prototype.oxc = {
            age: 123,
            name: 'oxc'
        }

        let b = new A()
        let c = new A()
// 这时候对b.oxc对象里面的属性进行修改,会影响到c.oxc对象,原因就在于oxc保存的是一个指向对象的地址,而b与c共享了这个地址,所以b与c持有同一个oxc对象
image.png
  1. 采用原型模式的话无法传递参数到构造函数中,导致所有创建出来的实例里面的属性都是一样的

原型模式和构造函数组合使用

        function A(name) {
            this.oxc = {
                name: name,
                age: 123
            }
        }
        A.prototype.sayName = function() {
            console.log(this.oxc.name)
        }

        let b = new A('oxc')
        let c = new A('大春春')
image.png

动态原型模式

        function A(name) {
            let mark = 0
            this.oxc = {
                name: name,
                age: 123
            }
            if (typeof this.sayName !== 'function') {
                mark++
                console.log(`已经创建了${mark}次`)
                A.prototype.sayName = function() {
                    console.log(this.oxc.name)
                }
            }
        }

        let b = new A('oxc')
        let c = new A('大春春')
// 该函数在创建第一次执行A的时候因为sayName方法是undefined,所以会在构造函数A的原型对象上设置sayName函数,而在第二次执行A的时候因为this.sayName已经被创建,所以就不执行了
image.png

寄生构造函数模式

        function S() {
            let value = new Array()
            value.push.apply(value, arguments)
            value.sum = function() {
                console.log(this.reduce((p, n) => p + n))
            }
            return value
        }
        let newArr = new S(1, 2, 3)
        newArr.sum()         //   6

稳妥构造函数模式

        function S(name) {
            let o = new Object()
            o.sayName = function() {
                console.log(name)
            }
            return o
        }
        let newObj = new S('oxc')
image.png

后记

然并卵,上面的模式其实工作中用得都比较少了,但是这些只是还是非常有意思的,现在工作中创建对象用得多是ES6推出Class了,当然了,Class那又是另外一个话题了,将在以后的博客中进行记录和学习.

上一篇 下一篇

猜你喜欢

热点阅读