深入 JS 对象属性
译者:前端小智作者:Dr.Axe l来源:2ality
阿里云最近在做活动,低至2折,有兴趣可以看看:
https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=pxuujn3r
为了保证的可读性,本文采用意译而非直译。
属性决定JS中对象的状态,本文章主要分析这些属性是如何工作的。
JS几种不同的属性
JS有三种不同的属性:数据属性,访问器属性和内部属性。
1.1 数据属性(`properties`)
对象的普通属性将字符串名称映射到值。例如,下面对象obj
有一个数据属性,名称为 prop
,对应的值为 123
:
var obj = {prop: 123
};
可以用以下方式读取属性的值:
console.log(obj.prop); // 123
console.log(obj["prop"]); // 123
当然也可以用以下方式来设置属性的值:
obj.prop = "abc";
obj["prop"] = "abc";
1.2 访问器属性
另外,可以通过函数处理获取和设置属性值。 这些函数称为访问器函数
。 处理获取的函数称为getter
。 处理设置的函数称为setter
:
var obj = {get prop () {return 'Getter';},set prop (value) {console.log('Setter: ' + value);}
}
访问 obj
属性:
> obj.prop'Getter'
> obj.prop = 123;Setter: 123
1.3 内部属性
一些属性只是用于规范,这些属于“内部”的属性,因为它们不能直接访问,但是它们确实影响对象的行为。内部属性有特殊的名称都写在两个方括号,如:
内部属性
[[Prototype]]
指向对象的原型。它可以通过Object.getPrototypeOf()
读取。它的值只能通过创建具有给定原型的新对象来设置,例如通过object.create()
或__proto__
。内部属性
[[Extensible]]
决定是否可以向对象添加属性。可以通过Object.isExtensible()
方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。可以通过Object.preventExtensions()
方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
2. 属性特性(attribute)
属性的所有状态,包括数据和元数据,都存储在特性(attribute)中。它们是属性具有的字段,就像对象具有属性一样。特性(attribute)键通常用双括号编写:
以下特性是属于数据属性:
[[Value]]
:该属性的属性值,默认为undefined
。[[Writable]]
:是一个布尔值,表示属性值(value
)是否可改变(即是否可写),默认为true
。
以下特性是属于访问器属性:
[[Get]]
:是一个函数,表示该属性的取值函数(getter),默认为undefined
[[Set]]
:是一个函数,表示该属性的存值函数(setter),默认为undefined
。
所有的属性都具有以下的特性:
[[Enumerable]]
:是一个布尔值,表示该属性是否可遍历,默认为true
。如果设为false
,会使得某些操作(比如for…in循环、Object.keys())跳过该属性。
[[Configurable]]
:是一个布尔值,表示可配置性,默认为true
。如果设为false
,将阻止某些操作改写该属性,比如无法删除该属性,也不得改变该属性的属性描述对象(value
属性除外)。也就是说,configurable
属性控制了属性描述对象的可写性。
3. 属性描述
JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息。下面是值为123
属性描述对象的一个例子。
{value: 123,writable: false,enumerable: true,configurable: false
}
咱们也可以通过访问器属性实现相同的目标,属性描述对象如下所示:
{get: function () { return 123 },enumerable: true,configurable: false
}
3.1 使用属性描述符的函数
下面的函数允许咱们使用属性描述符:
Object.defineProperty(obj, propName, propDesc)
:该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
obj
:要在其上定义属性的对象。prop
:要定义或修改的属性的名称。descriptor
:将被定义或修改的属性描述符。
var obj = Object.defineProperty({}, "foo", {value: 123,
})
Object.defineProperties(obj, propDescObj)
: 该方法直接在一个对象上定义一个或多个新的属性或修改现有属性,并返回该对象。
obj
: 将要被添加属性或修改属性的对象
props
: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置
var obj = Object.defineProperties({}, {foo: { value: 123, enumerable: true },bar: { value: "abc", enumerable: true }
});
Object.create(proto, propDescObj?)
: 方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
。
proto
:新创建对象的原型对象。propDescObj
:可选。如果没有指定为 undefined
,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()
的第二个参数。
var obj = Object.create(Object.prototype, {foo: { value: 123, enumerable: true },bar: { value: "abc", enumerable: true }
})
Object.getOwnPropertyDescriptor(obj, propName)
: 该方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
obj
:需要查找的目标对象prop
:目标对象内属性名称
var o, d;o = { get foo() { return 17; } };
d = Object.getOwnPropertyDescriptor(o, "foo");
// d {
// configurable: true,
// enumerable: true,
// get: /*the getter function*/,
// set: undefined
// }
4.可枚举性(Enumerable)
本节说明哪些操作受可枚举性影响,哪些操作不受可见性影响。 下面,假设有以下定义:
var proto = Object.defineProperties({}, {foo: { value: 1, enumerable: true },bar: { value: 2, enumerable: false }
})var obj = Object.create(proto, {baz: { value: 1, enumerable: true },gux: { value: 2, enumerable: false}
})
请注意,对象(包括proto
)通常至少具有原型Object.prototype
:
> Object.getPrototypeOf({}) === Object.prototypetrue
Object.prototype
是定义标准方法(如toString
和hasOwnProperty
)的地方。
4.1 受可枚举性影响的操作
可枚举性仅影响两个操作:for-in
循环和Object.keys()
。
for-in
循环遍历所有可枚举属性的名称,包括继承的属性(请注意,Object.prototype
的所有非可枚举属性都不会显示):
> for (var x in obj) console.log(x);bazfoo
Object.keys()
返回所有自有(非继承)可枚举属性的名称:
> Object.keys(obj)[ 'baz' ]
如果需要所有属性的名称,则需要使用Object.getOwnPropertyNames()
。
4.2 忽略可枚举性的操作
除了上述两个,其他操作都忽略了可枚举性,还有一些操作会考虑继承:
> "toString" in obj
true
> obj.toString
[Function: toString]
还有一些仅读取自有属性:
> Object.getOwnPropertyNames(obj)
[ 'baz', 'qux' ]> obj.hasOwnProperty("qux")
true
> obj.hasOwnProperty("toString")
false> Object.getOwnPropertyDescriptor(obj, "qux")
{ value: 2,writable: false,enumerable: false,configurable: false }
> Object.getOwnPropertyDescriptor(obj, "toString")
undefined
创建,删除和定义属性仅影响原型链中的第一个对象:
obj.propName = value
obj["propName"] = valuedelete obj.propName
delete obj["propName"]Object.defineProperty(obj, propName, desc)
Object.defineProperties(obj, descObj)
5. 最佳实践
一般规则是系统创建的属性是不可枚举的,而用户创建的属性是可枚举的:
> Object.keys([])
[]
> Object.getOwnPropertyNames([])
[ 'length' ]
> Object.keys(['a'])
[ '0' ]
这特别适用于原型对象中的方法:
> Object.keys(Object.prototype)
[]
> Object.getOwnPropertyNames(Object.prototype)
[ hasOwnProperty','valueOf','constructor','toLocaleString','isPrototypeOf','propertyIsEnumerable','toString' ]
因此,对于咱们的代码,应该忽略可枚举性。通常不应该向内置原型和对象添加属性,但如果这样做,咱们就应该使它们不可枚举以避免破坏内置代码。
正如咱们所看到的,非可枚举性主要受益于for-in
并且确保使用它的遗留代码不会中断。 不可枚举的属性创建了一种错觉,即for-in
仅迭代用户创建的对象自有的属性。 在咱们的代码中,如果可以,应该避免使用for-in
。
原文:https://2ality.com/2012/08/instanceof-object.html
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
交流
我是小智,公众号「大迁世界」作者,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!
关注公众号,后台回复福利,即可看到福利,你懂的。
每次整理文章,一般都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励
深入 JS 对象属性相关推荐
- php json 遍历 keys,详解javascript遍历json对象的key和任意js对象属性的示例代码(图)...
下面小编就为大家带来一篇javascript遍历json对象的key和任意js对象属性实例.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧 使用 keys 方法获取该对象 ...
- JS 对象属性的两种表示方法
JS中对象属性的表示方法有两种: <prop为属性名> obj.prop obj['prop'](注:'[]'里面必须是字符串) 例: var obj = {name:'abc' } ob ...
- JavaScript对象详解,js对象属性的添加
目录 一,什么是对象? 二,创建一个对象 三,对象的嵌套 四,对象的属性与修改 1,使用点.运算符 2,使用[]符号 3,修改属性 五,给对象添加属性 六,查看与删除对象的属性 1,使用Object. ...
- JS对象属性writable、enumerable、configurable
输出是什么? const person = { name: "Lydia" };Object.defineProperty(person, "age", { v ...
- html下拉框属性js,Html下拉框Js对象属性方法总结
var obj = document.getElementById("selectId"); 一 select属性: length ----------> 顾名思义字指的是下 ...
- js 对象属性过滤方法
数组使用fliter 函数是可以过滤掉的,但是对象的属性怎么过滤呢? 剔除少数属性,要多数属性 有时候需要剔除少数属性,留下大多数.类似于TS的omit 例子: let person = {name: ...
- react,删除js对象属性
const { data, setData } = useState()const XXX = ( id ) => {request({url: 'XXX',method: 'post',dat ...
- js for in遍历对象_JS中轻松遍历对象属性的几种方式
自身可枚举属性 Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 .如果对象的键-值都 ...
- JS对象、字符串以及数组之间的相互转换
1.对象转字符串 const obj = {id: 0,name: '张三',age: 12 } const objToStr = JSON.stringify(obj) console.log('o ...
最新文章
- 基于SSM实现的民宿网站系统
- 小型Web应用扫描工具Grabber
- MacBook Air m1的内存
- 技术宝典 | NeCodeGen:基于 clang 的源到源转译工具
- vue-cli3中的vue.config.js配置
- 25条提高iOS App性能的建议和技巧
- 计算机通信网填空题答案 与rs232接口相比,x.21接口,2020年自考计算机网络与通信问答题及答案:第三章...
- 剑指Offer——把字符串转换成整数
- autohotkey -- AHK 替换 4 为 $ 方便脚本编写
- Windows Server 2003 SP2(32位) 中文版 下载地址 光盘整合方法
- Unity发布WebGL之后读取StreamingAssets文件路径数据
- 软件项目管理中的需求管理要以用户为中心
- 名悦集团:冬季汽车开暖风有哪些注意事项
- (闪存)存储基础知识
- 辅警是事业编制吗?辅警会纳入事业编制吗?
- 人民大学 环境学院 雷洋(1987-2016)
- python pexpect使用介绍
- 基础 -- 网络相关单位换算(Mbps,Kbps,MBps等)
- 思科服务器windows系统时间设置,cisco交换机时间设置时间
- pinctrl和gpio子系统