博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Object properties in JavaScript
阅读量:5231 次
发布时间:2019-06-14

本文共 9846 字,大约阅读时间需要 32 分钟。

 

 Blog post “
” (
Object.preventExtensions(), Object.seal(), Object.freeze()

  

).

Properties determine the state of an object in JavaScript. This blog post examines in detail how they work.

Kinds of properties

JavaScript has three different kinds of properties: named data properties, named accessor properties and internal properties.

Named data properties (“properties”)

“Normal” properties of objects map string names to values. For example, the following object 
obj has a data property whose name is the string 
"prop" and whose value is the number 123.
var obj = {        prop: 123    };

  

You can get (read) a property:
console.log(obj.prop); // 123    console.log(obj["prop"]); // 123

  

And you can set (write) a property:
obj.prop = "abc";    obj["prop"] = "abc";

  

Named accessor properties

Alternatively, getting and setting a property value can be handled via functions. Those functions are called accessor functions. A function that handles getting is called a getter. A function that handles setting is called a setter.
var obj = {        get prop() {            return "Getter";        },        set prop(value) {            console.log("Setter: "+value);        }    }

  

Let’s interact with 
obj:
> obj.prop    'Getter'    > obj.prop = 123;    Setter: 123

  

Internal properties

Some properties are only used by the specification. They are called “internal”, because they are not directly accessible via the language, but they do influence its behavior. Internal properties have special names that are written in double square brackets. Two examples:
  • The internal property [[Prototype]] points to the prototype of an object. It can be read via Object.getPrototypeOf(). Its value can only be set by creating a new object that has a given prototype, e.g. via Object.create() or __proto__.
  • The internal property [[Extensible]] determines whether or not one can add properties to an object. It can be read via Object.isExtensible(). It can be set false via Object.preventExtensions(). Once false, it cannot be becometrue again.

Property attributes

All of the state of a property, both its data and its meta-data, is stored in 
attributes. They are fields that a property has, much like an object has properties. Attribute keys are often written in double brackets.

The following attributes are specific to named data properties:

  • [[Value]] hold the property’s value, its data.
  • [[Writable]] holds a boolean indicating whether the value of a property can be changed.
The following attributes are specific to named accessor properties:
  • [[Get]] holds the getter, a function that is called when a property is read. That function computes the result of the read access.
  • [[Set]] holds the setter, a function that is called when a property is set to a value. The function receives that value as a parameter.
All properties have the following attributes:
  • [[Enumerable]] holds a boolean. Making a property non-enumerable hides it from some operations (see below).
  • [[Configurable]] holds a boolean. If false, you cannot delete a property, change any of its attributes (except [[Value]]) or convert between data property and accessor property. In other words, [[Configurable]] controls the writability of a property’s meta-data.

Default values

If you don’t specify attributes, the following defaults are used:

 

Attribute key Default value
[[Value]] undefined
[[Get]] undefined
[[Set]] undefined
[[Writable]] false
[[Enumerable]] false
[[Configurable]] false

These defaults are especially important for property descriptors (see below).

Property descriptors

A property descriptor encodes the attributes of a property as an object. Each of the properties of that object corresponds to an attribute. For example, the following is the descriptor of a read-only property whose value is 123:
{        value: 123,        writable: false,        enumerable: true,        configurable: false    }

  

You can achieve the same goal, immutability, via accessors. Then the descriptor looks as follows:
{        get: function () { return 123 },        enumerable: true,        configurable: false    }

  

Functions that use property descriptors

The following functions allow you to work with property descriptors:
  • Object.defineProperty(obj, propName, propDesc)

      

    Create or change a property on obj whose name is propName and whose attributes are specified via propDesc. Return the modified object. Example:
    var obj = Object.defineProperty({}, "foo", {        value: 123,        enumerable: true        // writable and configurable via defaults    });

      

  • Object.defineProperties(obj, propDescObj)
    The batch version of Object.defineProperty(). Each property of propDescObjholds a property descriptor. The names of the properties and their values tellObject.defineProperties what properties to create or change on obj. Example:
    var obj = Object.defineProperties({}, {        foo: { value: 123, enumerable: true },        bar: { value: "abc", enumerable: true }    });

      

  • Object.create(proto, propDescObj?)
    First, create an object whose prototype is proto. Then, if the optional parameter propDescObj has been specified, add properties to it – in the same manner as Object.defineProperties. Finally, return the result. For example, the following code snippet produces the same result as the previous snippet:
    var obj = Object.create(Object.prototype, {        foo: { value: 123, enumerable: true },        bar: { value: "abc", enumerable: true }    });

      

  • Object.getOwnPropertyDescriptor(obj, propName)
    Returns the descriptor of the own (non-inherited) property of obj whose name is propName. If there is no such property, undefined is returned.
    > Object.getOwnPropertyDescriptor(Object.prototype, "toString")    { value: [Function: toString],      writable: true,      enumerable: false,      configurable: true }    > Object.getOwnPropertyDescriptor({}, "toString")    undefined

      

Enumerability

This section explains which operations are influenced by enumerability and which aren’t. Below, we are assuming that the following definitions have been made:
var proto = Object.defineProperties({}, {        foo: { value: 1, enumerable: true },        bar: { value: 2, enumerable: false }    });    var obj = Object.create(proto, {        baz: { value: 1, enumerable: true },        qux: { value: 2, enumerable: false }    });

  

Note that objects (including 
proto) normally have at least the prototype
Object.prototype  :
> Object.getPrototypeOf({}) === Object.prototype    true

  

Object.prototype is where standard methods such as 
toString and 
hasOwnProperty are defined.

Operations affected by enumerability

Enumerability only affects two operations: The for-in loop and 
Object.keys().

The for-in loop iterates over the names of all enumerable properties, including inherited ones (note that none of the non-enumerable properties of Object.prototype show up):

> for (var x in obj) console.log(x);    baz    foo

  

Object.keys() returns the names of all own (non-inherited) enumerable properties:

> Object.keys(obj)    [ 'baz' ]

  

If you want the names of all own properties, you need to use
Object.getOwnPropertyNames() (see example below).

Operations that ignore enumerability

All other operations ignore enumerability. Some read operations take inheritance into consideration:
> "toString" in obj    true    > obj.toString    [Function: toString]

  

Other read operations only work with own properties:
> 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

  

Creating, deleting and defining properties only affects the first object in a prototype chain:
obj.propName = value    obj["propName"] = value    delete obj.propName    delete obj["propName"]    Object.defineProperty(obj, propName, desc)    Object.defineProperties(obj, descObj)

  

Best practices

The general rule is that properties created by the system are non-enumerable, while properties created by users are enumerable:
> Object.keys([])    []    > Object.getOwnPropertyNames([])    [ 'length' ]    > Object.keys(['a'])    [ '0' ]

  

That especially holds for the methods in prototype objects:
> Object.keys(Object.prototype)    []    > Object.getOwnPropertyNames(Object.prototype)    [ hasOwnProperty',      'valueOf',      'constructor',      'toLocaleString',      'isPrototypeOf',      'propertyIsEnumerable',      'toString' ]

  

Thus, for your code, you should ignore enumerability. You normally shouldn’t add properties to built-in prototypes and objects, but if you do, you should make them non-enumerable to avoid breaking code.

As we have seen, non-enumerability mostly benefits for-in and ensures that legacy code using it won’t break. The non-enumerable properties create the illusion that for-in only iterates over the user-created own properties of an object. In your code, you should avoid for-in if you can .

If you use objects as maps from strings to values, you should only work with own properties and ignore enumerability. But there are more pitfalls for this use case .

Conclusion

In this post, we have examined the nature of properties, which is defined via so-called attributes. Note that actual JavaScript implementations do not necessarily organize properties via attributes, they are mainly an abstraction used by the ECMAScript specification. But one that is sometimes visible in the language itself, for example in property descriptors.

Further reading on 2ality:

  • Read “” for more information on how inheritance and enumerability affect property-related operations.
  • Read “” for an introduction to JavaScript inheritance.

References

转载于:https://www.cnblogs.com/hephec/p/4589999.html

你可能感兴趣的文章
「Unity」委托 将方法作为参数传递
查看>>
重置GNOME-TERMINAL
查看>>
redis哨兵集群、docker入门
查看>>
hihoCoder 1233 : Boxes(盒子)
查看>>
oracle中anyData数据类型的使用实例
查看>>
C++对vector里面的元素排序及取任意重叠区间
查看>>
软件测试——性能测试总结
查看>>
12.4站立会议
查看>>
Java Concurrentmodificationexception异常原因和解决方法
查看>>
客户端访问浏览器的流程
查看>>
codeforces水题100道 第二十二题 Codeforces Beta Round #89 (Div. 2) A. String Task (strings)
查看>>
c++||template
查看>>
[BZOJ 5323][Jxoi2018]游戏
查看>>
编程面试的10大算法概念汇总
查看>>
Vue
查看>>
python-三级菜单和购物车程序
查看>>
条件断点 符号断点
查看>>
VMware12 + Ubuntu16.04 虚拟磁盘扩容
查看>>
设计模式——设计模式概述
查看>>
封装一个获取module.exports内容的方法
查看>>