前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >了解JavaScript对象的特殊属性

了解JavaScript对象的特殊属性

作者头像
努力的Greatiga
发布2022-07-25 10:18:32
7000
发布2022-07-25 10:18:32
举报
文章被收录于专栏:前端开发与网站建设

理解对象

面向对象最常见的方式就是类,定义一个类之后,由它创建的对象都拥有从类继承而来的方法与属性。然而 JavaScript 里面,至少在 ES6 之前是没有 class的概念的。所以它的对象与传统类的对象还是有区别的。

Js 的对象可以说是一组无序值的集合,可以包括基本类型值、引用类型值、函数

通常采用字面量的方式或者 new Object() 的方式来创建;创建时除定义的值外,还具有一些特殊值,用来定义对象的各种行为。

属性类型

JS 规定了许多属性值用于给引擎使用,但是不能直接访问他们,通常用 [[Value]] 的方式放置

数据属性

四个值,用来描述行为

  • [[Configurable]]:能否用 delete 删除某个属性,是否可以修改属性的特性,能否改为访问器属性,字面量创建的对象默认值为 true
  • [[Enumerable]]:能否通过 for-in 遍历属性名字,默认为 true
  • [[Writable]]:能否直接修改某个属性的值,默认为 true
  • [[Value]]:读数据时从这读取,写入时放在这里,默认为 undefined

Object.defineProperty()

该方法可以设置上述的特殊值,接受三个参数,参数1 为要修改的对象,参数2 为修改的对象,参数3 可以指定多个特殊值的值

  • 如果是对已有属性操作,则改变相应的特殊值就行
  • 如果没有该属性,则认为是通过该方法添加新属性,此时应该显式的定义各项值,否则就会默认为 false

看实例,允许直接通过该方法定义属性并直接指定对应的特殊值,若没指定的特殊值则按false ,要想让默认值为 true,需要用字面量或 new Object() 来创建

  • 修改 Writable 属性,在严格模式下, writable 值为false时,修改属性值会报错
代码语言:javascript
复制
var great = {}
var x = {
  name: 'Great'
}
Object.defineProperty(great,'name',{
  writable: false,//设置 name 属性值不可修改
  value: "Greatiga"
});
console.log(x.name,great.name);//Great Greatiga
x.name = "yes";
great.name = "no";
console.log(x.name,great.name);//yes Greatiga
  • 修改 Configurable 属性
代码语言:javascript
复制
var great = {}
Object.defineProperty(great,'name',{
  configurable: false,//设置 name 属性值不可删除
  value: "Greatiga"
});
console.log(great.name);//Greatiga
delete great.name;
console.log(great.name);//Greatiga

但是,Configurable 属性一旦被定义为 false,就不能再变为 true 了,同时 Enumberable 属性也不可修改

代码语言:javascript
复制
var great = {}
Object.defineProperty(great,'name',{
  configurable: false,//设置 name 属性值不可删除,
  enumerable: true,
  writable: true,
  value: "Greatiga"
});

Object.defineProperty(great,'name',{
  writable: false
});
//正常不会报错

Object.defineProperty(great,'name',{
  configurable: true
});
//报错
//Cannot redefine property: name
//   at Function.defineProperty (<anonymous>)
//   at <anonymous>:6:8

Object.defineProperty(great,'name',{
  enumerable: false
})
//报错
//Uncaught TypeError: Cannot redefine property: name
//  at Function.defineProperty (<anonymous>)
//  at <anonymous>:11:8

访问器属性

访问器属性只能通过 Object.defineProperty() 定义,通过字面量定义不是

四个值

  • [[Configurable]]:能否用 delete 删除某个属性,是否可以修改属性的特性,能否改为访问器属性,字面量创建的对象默认值为 true
  • [[Enumerable]]:能否通过 for-in 遍历属性名字,默认为 true
  • [[Get]]:读取数据时调用的函数,默认为 undefined
  • [[Set]]:写入数据时调用的函数,默认为 undefined

Object.defineProperty()

  • 但一个属性添加了 get 和 set 方法后,该属性就是一个访问器属性,读取时触发 get ,设置值时触发 set
  • set 指向了 setter方法,get 指向了 getter 方法
  • 约定属性名前面加上 _ 作为私有变量,即外部不可以直接访问,需要通过 get 与 set 来访问,(事实上也是可以直接访问的,因为都是普通变量,但是既然约定,那么我们在编写我们的对象时,就应该遵守约定,哪些可以给外部看到,哪些对于外部隐藏)
代码语言:javascript
复制
var Great = {
  _age: 20
}
Object.defineProperty(Great,"age",{
  get: function() {
    console.log('get');
    return this._age;
  },
  set: function(s) {
    console.log('set');
    this._age += s;
  }
});
Great._age = 25;//同样可以通过直接访问属性改变值,但是不要这样,要遵守规定
console.log(Great.age)//25
Great.age = 1;
console.log(Great.age)//26

getter 与 setter 不一定都要定义,只定义了 get 表示只能读,反之表示只能写

代码语言:javascript
复制
var Great = {
  _age: 20
}
Object.defineProperty(Great,"age",{
  get: function() {
    console.log('get');
    return this._age;
  }
});
Great._age = 25;
console.log(Great.age)//25
Great.age = 21;
console.log(Great.age)//25 显然上面这一步没有赋值成功,因为没有定义 set

IE8 对 Object.defineProperty() 的实现并不全面,建议不要使用在这个版本

defineGetterdefineSetter

另一种定义访问器属性的方式

例子

代码语言:javascript
复制
var Great = {
  _age: 20
}
Great.__defineGetter__("age", function() {
  console.log('get');
  return this._age;
});

同时定义多个属性

Object.defineProperties() 方法

代码语言:javascript
复制
var Great = {}
Object.defineProperties(Great,{
  name: {
    writable: true,
    enumerable: true,
    configurable: true,//允许修改另外两个属性,因为他们默认为 false
    value: 'Greatiga'
  },
  _time: {
    configurable: true,//允许修改另外两个属性,因为他们默认为 false
    value: 2020
  },
  time: {
    configurable: true,//允许修改 set 和 get,因为他们默认为 false
    get: function() {
      return this._time
    },
    set: function(time) {
      this._time = time;
    }
  }
});
Great.name = 'Link';
Great.time = 1999;
console.log(Great.name,Great.time);//Link 2020 
//很显然_time的值并未修改,因为默认都为 false,writable 为 false;所以不许修改其值

Object.defineProperties(Great,{
  name: {
    writable: false, //将此属性设为不可更改
    enumerable: false //禁止遍历
  },
  _time: {
    writable: true, //允许修改
    enumerable: true //允许遍历
  },
  time: {
    enumerable: true, //允许遍历
    set: function(time) { //重写 set 方法
      this._time = time + 10;
    }
  }
});

Great.name = "GG";
Great.time = 1999;
console.log(Great.name,Great.time);//Link 2009
//此时 _time 可以修改了,但是 name 被我们禁止修改了

警惕: 上面的例子中,如果一开始没有设置 configurable 为 true,那么后面的步骤除了修改 writable 以外,修改其他特殊属性以及重写 set 方法都会报错,因为这个 configurable 就是规定每个属性在第一次设置之后是否可以再次修改

Uncaught TypeError: Cannot redefine property: 属性名 -> 这是通常的报错信息,表示不能重新定义特殊属性

获取对象属性的特殊属性值

Object.getOwnPropertyDescriptor()

接受两个参数,参数1位对象,参数2为属性值。返回一个对象,里面包括了之前介绍的各种 property 值

代码语言:javascript
复制
var Great = {}
Object.defineProperties(Great,{
  name: {
    writable: true,
    configurable: true,
    value: 'Greatiga'
  },
  _time: {
    configurable: true,
    value: 2020
  },
  time: {
    configurable: true,
    get: function() {
      return this._time
    }
  }
});
var t1 = Object.getOwnPropertyDescriptor(Great,'name');
var t2 = Object.getOwnPropertyDescriptor(Great,'time');
console.log(t1.writable,t1.enumerable,t1.set);//true false undefined
console.log(t2.writable,t2.configurable,typeof t2.get);//undefined true "function"

总结

首先来看看数据属性与访问器属性是否可以同时定义

代码语言:javascript
复制
var test = {}
Object.defineProperty(test,'name',{
  writable: true,
  configurable: true,
  get: function() {
    return this.name;
  }
})
//报错
//Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute,

这样一看就明白了,数据属性是定义某个属性的读取写入功能的,而访问器属性则是用来间接读取写入对象中的属性

所以这很像 公有变量与私有变量,如果要在对象中定义对外开放的变量,此时可以用数据属性来规定它,如果你想定义一个不对外公开的变量,就用访问器属性规定它

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 理解对象
  • 属性类型
  • 数据属性
    • 四个值,用来描述行为
      • Object.defineProperty()
      • 访问器属性
        • 四个值
          • Object.defineProperty()
            • defineGetter 和 defineSetter
            • 同时定义多个属性
              • Object.defineProperties() 方法
              • 获取对象属性的特殊属性值
                • Object.getOwnPropertyDescriptor()
                • 总结
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档