JavaScript对象理解

这几天又好好读了JavaScript高级程序设计。其中在理解对象和创建对象这块有了很多新的见解和认知

JavaScript的对象

由于我最开始学习的是Java,所以很容易就会把JavaScript和Java联系到一起。不同于Java中,ES5还是没有类这个概念的。没办法通过类来实例化对象,更别说什么构造函数继承这些了。

ECMA-262把对象定义:无序属性的集合,其属性可以包含基本值,对象或者函数。

简单地创建对象

JavaScript创建对象很简单,最基本的创建方法:

    var obj = new Object();  // 通过Object构造函数来创建对象
    // 或者
    var obj2 = {//....balabala} // 通过对象字面量来创建对象

创建一个对象后,我们来了解一下对象的属性类型:

对象的属性类型

数据属性:

数据属性说的简单点就是对象中具有具体数据值的属性。如下中,name,age均为person的数据属性。

    var person = {
      name: 'www',
      age: 18 
    }

每一个数据属性呢,又包含四个属性值。显示在对象中的是其value属性。可以由Object.defineProperty来定义它的这四个属性。
四个属性:

1、configurable : 表示这个属性是否是可配置的。默认为true,如果修改为false,那么不可再修改这个属性的configurable属性和enumerable属性,也不可用delete来删除这个属性。
2、enumerabel : 表示这个属性是否是可枚举的。默认为true。在比如Array这种引用类型中,它的那些例如sort(),push()等等的方法的这个属性均为false,这样我们就没办法用for in 来枚举处其属性。
3、writable: 表示是否可修改。默认为true。如果改为false,那么就没办法再修改这个属性值。
4、value : 表示这个属性的属性值。上面的name的value属性就死 'www'。

Object.defineProperty方法的使用:

    Object.defineProperty(person,name,{
        // 这里我就取默认情况
        configurable: true,
        enumerable: true,
        writable: true,
        value: 'www'
    })
访问器属性

访问器属性没有具体的数据值,它提供一个getter和setter方法。
 这个就有点绕了。因为我们在定义对象的时候,像上面person这种,它的name属性我们是可以看得到的,很明显就容易理解数据属性。那么具体什么叫做访问器属性呢?
 这里通过一个例子来说明一下。首先我们定义一个girl对象。女孩子的年龄都是保密的,所以我们给它设置一个_age属性。那我们可以通过一个ask访问器属性来获取到这个女孩的年龄。

    var girl = {
      _age:18, // 下划线_开头的属性是一种约定俗成,一般不作为公开属性, 只能通过对象方法访问。
      mood: "happy"      
    }
    // 定义一个ask访问器属性。
    Object.defineProperty(girl,"ask",{
      // 我们可以通过girl.ask 来获取到这个女孩18岁了。
      get: function () {
         return this._age;
      } 
      // 要是我们给这个女孩设置一个 girl.ask = 20; 就像询问这个女孩,你是不是20了?女孩就会很生气。    
         她的mood属性就会变成 angry。
      set: function(val) {
        if(val > 18) {
          this.mood = "angry";
        }
      }
    })

这就是访问器属性。可以通过这个属性获取到其他属性,也可以在设置这个属性的时候,导致别的属性发生变化。同时,这个属性除了get和set两个属性,还有configurable和enumerable两个属性,类似于数据属性。
关于读取属性和设置多个属性等,这些都是基本知识的介绍,可以阅读《JavaScript高级程序设计》

高级程序设计

创建对象

上面说了很简单通过Object构造函数和对象字面量来创建对象。接下来说几个逼格稍微高一点的。

工厂模式

JavaScript工厂模式创建对象就像是无限调用一个方法来创建Object对象。这个方法就像是一个工厂一样,如下代码所示:

    function factory(name,age,sex) {
      var o = new Object();
      o.name = name;
      o.age = age;
      o.sex = sex;
      o.say = function () {
          console.log(o.name+'--'+o.age+'--'+o.sex);
      }
     return o;
  }
  // 创建实例对象
  var p1 = factory("wyh",18,"man");
  p1.say(); // wyh--18--man

缺点:缺点太明显了,我创造的对象全是Object的,没有标识度。实例化的p1,p2,p3也没有任何的联系。
所以,让我们来看构造函数模式。

构造函数模式

还是没办法摒弃Java的学习思想。所以这里我很容易就联想到Java的构造函数。JavaScript的构造函数模式创建对象还真的很像Java的构造函数。如下代码:

    // 与Java的构造函数何其相似。函数内部没有显示的创建对象的动作。 
    function Animal(name,leg) {
        this.name = name;
        this.leg = leg;
        this.sayName = function () {.....};
    }
    // 实例化两个对象:通过new 来创建。
    var tiger = new Animal("tiger",4);
    var lion = new Animal("lion",4);
    console.log(tiger.constructor); // Function: Animal。   

好像很不错。可是有严重的问题所在。每当实例化一个Animal对象,就会给sayName开辟一个内存空间,如果这个对象有很多函数属性,如果要实例化很多的Animal对象,就会很占用内存空间了。当然,我们可以把这个对象的函数属性放在全局变量中,但是同时也会污染了全局环境。
所以,来看原型模式:

原型模式

由于我们创建的每个函数都是有一个叫做prototype(原型)的属性,该属性作为一个指针指向一个对象。
所以我们可以利用这个prototype来进行创建对象。这里仅仅介绍简单的原型模式创建,更具体的可以阅读《JavaScript高级程序设计》。
代码:

    function Person() {
    }
    Person.prototype.name = "wyh";
    Person.prototype.age = 18;
    Person.prototype.list = [],
    Person.prototype.sayName = function () {
        console.log(this.name);
    }
    var p1 = new Person();
    var p2 = new Person();
    p1.list.push("a");
    console.log(p2.list) // ['a']
    console.log(p1.constructor)  // Person
    console.log(p1.sayName == p2.sayName) // true;

解决了上面构造函数模式中的函数占用内存的问题了。因为所有实例化的对象的函数指向的地址是一样的。
缺点:没有办法自定义初值,不具变通能力。
如上面所示,我在p1中操作了数组list,p2的也发生改变,这是不想看到的。原型模式一个实例化对象更改引用类型,所有的都会改变。

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

既然构造函数和原型模式都各自有问题,而且还可以互补。那么我们就把这两种模式结合到一起使用。
代码如下所示:

    function Person(name,age,sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.shoplist = [];
    }
    Person.prototype = {
        sayName: function () {
            console.log(this.name);
        },
        constructor: Person
    }

    var p1 = new Person("wyh",18,"man");
    var p2 = new Person("MJ",16,"wm");
    p1.shoplist.push("apple");
    p2.shoplist.push("shoes");
    console.log(p1.sayName == p2.sayName); // true
    console.log(p1.constructor) // Person
    console.log(p2.shoplist) // ['shoes']

我们把公用的方法用原型模式构造,省去内存消耗。把不公用的引用类型用构造函数模式构造,避免混淆。
同时,也可以通过传入初始化数据来自定义我们需要的对象的样子。
这种方法(模式)是使用度最普遍的一种方法。

动态原型模式

把上面那种模式中,所有的信息都封装在构造函数中。但是又为了防止重复的初始化原型,于是就有了动态原型模式。话不多说,请看代码:

    function Person(name,age) {
        // 属性
        this.name = name;
        this.age = age;
        // 动态地进行原型的构造方法
        if(typeof this.sayName != "function") {
            console.log('----1------');
            Person.prototype.sayName = function () {
                   console.log(this.name);
            }
            // 其他的需要原型处理的属性
        }
    }

    var p1 = new Person("wyh",18); // 1
    p1.sayName(); // wyh
    var p2 = new Person("mj",16); // 什么都没有
    p2.sayName(); // mj

当我们第一次实例化Person的时候,会动态地创建原型属性,并且只创建这一次。

寄生构造函数模式

这个。。。我看不太出来和工厂模式的区别。要说实例化的时候用了new操作符的话,那我还是不明白这个模式的作用所在。

稳妥构造函数模式

同上面这个寄生构造函数模式,我暂时看不出来它的用处所在。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,063评论 6 510
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,805评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,403评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,110评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,130评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,877评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,533评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,429评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,947评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,078评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,204评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,894评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,546评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,086评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,195评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,519评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,198评论 2 357

推荐阅读更多精彩内容