《你不知道的JavaScript》之对象二

接下来继续讨论对象的主要内容

一、属性描述符

对于对象中的属性,我们一般都是直接调用,但是属性本身又有什么特性呢,该怎么去描述?属性描述符就扮演了这样一种角色。属性描述符是在ES5以后才有的,看下面的代码。


  var myobjec = {

      a:2,

      };

      var descriptor = Object.getOwnPropertyDescriptor(myobjec,"a")

      console.log(descriptor);

      //返回的结果为一个object对象:

{

configurable:true

enumerable:true

value:2

writable:true

}


返回的对象中包含了四个描述符:configurable(可配置)、enumerable(可枚举)、value(值)、writable(可写入)。

这些属性描述符可以修改吗?当然,我们可以用Object.defineProperty(...)来添加一个新的属性或是修改一个已有属性。

1)writable

决定了属性是否可以被修改。如果将其设置为false,那么对应的value是不能被修改的。



      var myobject = {

          a:2,

      };

      Object.defineProperty(myobject,"a",{

      writable:false,

      configurable:true,

      enumerable:true,

      value:2

      })

      myobject.a = 4;

      console.log(myobject.a);//2


2)configurable(可配置)

只要是可配置,就可以用defineProperty来修改属性描述符。


      var myobject = {

         a:2,

      };

      myobject.a = 3;

      console.log(myobject.a ); //3

      Object.defineProperty(myobject,"a",{

      writable:true,

      configurable:false,

      enumerable:true,

      value:4

      });

      console.log(myobject.a);//4

      myobject.a = 5;

      console.log(myobject.a);//5

      Object.defineProperty(myobject,"a",{

      writable:false,

      configurable:false,

      enumerable:true,

      value:6

      });  //Uncaught TypeError


如果将configurable设置为false后,再去配置就会报“未捕获类型”错误。

3)enumerable(可枚举)

通常属性的这个描述符默认为true,比如在for循环中,便可以枚举此属性。如果你在循环遍历中不想让该属性出现,那么将它的configurable设置为false即可。

二、属性不可变性

很多时候,你都希望属性是不可变的,在ES5中可以通过很多方法来实现:

1)将属性描述符writable和configurable设置为false即可;

2)禁用:可以使用Object.preventExtensions(..)来禁止一个对象添加新属性并且保留已有属性;


    var myobject = {

       a:2,

      };

      Object.preventExtensions(myobject);

      myobject.b = 3;

      console.log(myobject.b);//undefined


3)密封:Object.seal(...),调用这个方法时会调用preventExtention,并把所有的属性都标记为configurable:false,什么意思呢?就是说调用密封方法后,任何为对象添加、删除新属性的操作都是不允许的,但是属性值可以被修改,

4)冻结:Object.freeze(),这个方法会调用seal方法,同时将writable标记为false,所以这个不能修改的级别就比较高了,不仅不能添加删除,而且也不能修改了。

三、[[get]] 和  [[put]]操作

在访问对象属性时,表面上我们只是获取了属性值这么简单,其实是在对象上进行了[[get]]操作,对象的内置方法 [[get]] 会查找对象中是否存在改属性,如果存在返回属性对应的值,如果不存在,其实会执行另外一种行为,就是查找[[ prototype ]]链,也就是原型链,这个后面会讲到。

如果无论如何都找不到这个属性,那么就会返回undefined。


      var myobject = {

      a:2,

      };

      console.log(myobject.b);//undefined

      console.log(c); //Uncaught ReferenceError: c is not defined


注意属性访问和变量访问的区别,如果对象中不存在属性,那么返回undefined,而变量在当前作用域中不存在的话,就会抛出 referenceError错误。原因就是属性访问调用了对象内置操作[[get]]。

对于[[put]]操作,你可能认为一般是在属性赋值时被调用,但实际情况并不完全这样,触发的原因有很多。不过首先要看对象中是否存在这个属性,如果存在的话,那么一般会检查下面的内容:

1)属性是否是属性描述符,如果是并且存在setter,就会调用setter,什么是setter呢,接下来会讲到;

2)属性描述符writable是否是false,如果是的话,在非严格模式下静默失败,在严格模式下抛出typeError错误;

3)如果上述情况都不是,那么将该值设置为属性值。

如果对象中不存在这个属性,那么[[put]]操作会查找原型链,这个后面会讲到。

四、getter 和  setter 操作

ES5中的getter和setter操作会改变对象属性的默认操作,但是只能应用在单个属性上而不是整个对象上。有的同学会问到,平时好像没有看到这两个方法啊?这是因为它们都是隐藏函数,都是在属性的获取和赋值时默默的调用的。

看下面这段代码:


var myobject = {

      get a(){

      return 2;

      }

      };

      console.log(myobject.a);//2

      Object.defineProperty(myobject,'b',{

      get:function(){

      return this.a*2;

      }

      })

      console.log(myobject.b);//4


上面两种定义getter的方法都使得在访问属性时调用了getter。不过既然有了getter,那么setter也不能少对吧。


var myobject = {

      get a(){

           return this._a;

      },

      set a(val){ 

            this._a = val*2;

           }

      };   

      myobject.a = 2;

      console.log(myobject.a); //4


到此为止,同上篇文章一起对对象的一些基本属性做了系列的讨论和讲解,相信勤奋好学的同学们有了更深刻的认识吧。

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

推荐阅读更多精彩内容

  • 来自:参 考 原 文 对象是由多个名/值对组成的无序的集...
    wyude阅读 1,247评论 1 7
  • 对象 对象可以通过两种形式定义: 声明形式和构造形式 声明形式语法: var myObj = {key:value...
    qhaobaba阅读 329评论 0 0
  • 尽管javascript里有大量内建引用对象,很可能你还说会频繁创建自己的对象。当你在这么做的时候,记得javas...
    WanLum阅读 527评论 1 3
  • 标签: js 还有原型链要更新呀 作用域 作用域是查找变量的一套规则 如果查找的目的是对变量进行赋值,则进行LH...
    一颗板栗_阅读 675评论 0 0
  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,550评论 0 5