📜 ⬆️ ⬇️

CoffeeScript: Methods for working with objects

CoffeeScript Object methods

In the 5th edition of ECMAScript for working with objects, many new methods have appeared, but their detailed description and internal implementation in Russian (often in English) is not so easy to find. It is for this reason that this article will examine and describe in detail all the methods of the Object object according to the 3rd and 5th editions of the ECMAScript specification.

Content

1. Object.create (proto [, properties])
2. Object.defineProperty (object, property, descriptor)
3. Object.defineProperties (object, properties)
4. Object.getOwnPropertyDescriptor (object, properties)
5. Object.keys (object)
6. Object.getOwnPropertyNames (object)
7. Data descriptor
8. Accessor descriptor
9. Object.getPrototypeOf (object)
10. Object.preventExtensions (object)
11. Object.isExtensible (object)
12. Object.seal (object)
13. Object.isSealed (object)
14. Object.freeze (object)
15. Object.deepFreeze (object) (non-standard)
16. Object.prototype.hasOwnProperty (property)
17. Object.prototype.isPrototypeOf (object)
18. Object.prototype.propertyIsEnumerable (object)
19. Conclusion

')

Object.create (proto [, properties])


Object.create () creates a new object with the specified prototype object and properties:

object = Object.create property: 1 object.property # 1 

The method can take two initializing parameters.
The first parameter is required, it specifies the prototype of the object and must be null or an object.
The second parameter is optional, it initializes the properties of the object.

Consider an example:

 object = Object.create {}, property: value: 1 object.property # 1 

In this example, we set the first parameter to an empty object, which will be the prototype object for the properties defined in the second parameter.

Do not be confused by the mysterious value property, a little later we will look at this topic in more detail.

So what is the difference between the first and second option?
I think that the answer to this question can clarify the following example:

 object = Object.create property: 1 object.property = 2 object.property # 2 object = Object.create {}, property: value: 1 object.property = 2 object.property # 1 

What the hell you ask?
Simply, the second form of writing by default implies that properties are read-only, they cannot be deleted and they cannot be listed!

Let's look at an example:

 object = Object.create {} property: value: 1 object.property = 2 object.property # 1 object.method = -> object.property do object.method # 1 key for key of object # method delete object.property # false 

As you can see, we failed to set a new value for the property, neither to list, nor to delete.

And now I would like to draw attention to the way prototype inheritance is implemented using Object.create () :

 A = a: 1 b: 2 B = Object.create A, c: value: 3 enumerable: on for own key, value of B console.log " # {key}: # {value}" # c:3, a:1, b:2 

In this example, we implemented property inheritance from object A , and added an enumerable attribute so that the property defined in object B can be listed in the for-of loop.

I want to note that the presence of the operator in the for-of statement avoids the use of the hasOwnProperty method in the body of the loop and prevents checking the properties in the object's prototype chain.
A more detailed description of this operator can be found in my previous article .

If you are interested in how the create () method works from the inside, then as a task to consolidate the read, I quote its implementation according to the specification :

 Object.create = (object, properties) -> # 1. If Type(O) is not Object or Null throw a TypeError exception. if typeof object is not 'object' throw new TypeError "Object.create: # {object.toString()} is not an Object or Null" # 2. Let obj be the result of creating a new object as if by the expression new Object() # where Object is the standard built-in constructor with that name __new__ = new Object # 3. Set the [[Prototype]] internal property of obj to O. if '__proto__' of init __new__.__proto__ = object; else __new__.constructor:: = object # 4. If the argument Properties is present and not undefined, add own properties # to obj as if by calling the standard built-in function Object.defineProperties # with arguments obj and Properties. if typeof props is not 'undefined' Object.defineProperties object, props # 5. Return obj. object 


Object.defineProperty (object, property, descriptor)


The Object.defineProperty () method allows you to define a new property of an object and / or modify the attributes of an existing property. A new object is returned as a result.

object - the object for which you want to define properties
property - the name of the property to be defined or modified.
descriptor - descriptor

Consider an example:

 object = {} Object.defineProperty object, 'property' value: 1 

At the same time, you probably already have questions regarding the use of the value property. Now we will try to highlight this issue in more detail.

With new methods in ECMAScript 5 , new terms have appeared, in particular, a user descriptor .

A descriptor is a simple object ( plain object ) that allows you to set values ​​and access level for your own properties, as well as store their description.

In other words, descriptors allow you to control the attributes of properties.
Before the advent of ECMAScript 5 , much more modest tools were available to us to work with the attributes of objects: Object.prototype.propertyIsEnumerable () and Object.prototype.hasOwnProperty () .

Formally, descriptors are divided into three types: data descriptors ( Data descriptors ), access descriptors ( Accessor descriptors ), and general descriptors ( Generic descriptors ).
However, we will not consider the last type of descriptors, since their description is more theoretical at the level of implementation than practical.

Data descriptor


This property is created if the descriptor is empty or the descriptor has one of two attributes: value or writable .
The internal method [[IsDataDescriptor]] is responsible for checking the presence of attributes:

 IsDataDescriptor (Descriptor): if Descriptor is undefined return off if !Descriptor.[[Value]] and !Descriptor.[[Writable]] return off return on 

In addition to the required attributes, there are optional attributes in the data descriptor: configurable and enumerable .

 { configurable: false, enumerable: false } 

Now let's look at all the attributes individually:

value - sets the value of the object property.
writable - defines the possibility of changing the property.
configurable - defines the ability to delete a property.
enumerable - determines the accessibility of listing properties

Inside the implementation, these attributes have the following names: [[Value]] , [[Writable]] , [[Enumerable]] , [[Configurable]] .

By default, all data descriptor attributes are false , except for the value attribute, its value is set to undefined .

Note: formally, in ECMAScript 3 there are no user descriptors, but there are internal attributes DontEnum , ReadOnly and DontDelete .

Thus, we ourselves can set similar attributes for object properties:

 Object.defineProperty {}, 'property' value: 1 writable: on enumerable: on configurable: on 

And now let's imagine that we needed to expand the Object prototype:

 Object::method = -> @ 

So we added a new method to the Object prototype and can continue to use it.
In fact, this solution has a lot of disadvantages.

Firstly, there is a possibility that a method with the same name may appear in a future standard and our method will override it. As an option, you can give the method some intricate name and sleep well.

For example:

 Object::my_super_method = -> @ 

It is unlikely that a method with this name will ever fall into the specification.

Secondly, everything that we add to the prototype Object gets into other objects:

 Object::method = -> 1 list = [] do list.method # 1 

Third, such a method will have a value of true for the enumerable attribute:

 Object::method = -> 1 object = {}; i for i of object # method 

You can prevent the enumeration of the method method in an object as follows:

 i for own i of object 

Despite the fact that this solution works well, it can be improved at the stage of adding a method to the Object prototype:

 Object.defineProperty Object::, 'method' value: -> 1 enumerable: false i for i of object # 

As you can see, the method was not listed in the for-of statement.

Although the expansion of prototype base types is not always good practice, this need sometimes arises. Therefore, for your part, try to take all reasonable measures so that you do not step on your own rake, especially if other people will work with your code.

Accessor descriptors


An access descriptor is one in which the get or set attribute is present. In this case, the presence of these attributes together. However, the presence of the attributes value and writable is unacceptable :

 IsDataDescriptor (Descriptor): if Descriptor is undefined return off if !Descriptor.[[Get]] and !Descriptor.[[Set]] return off return on 

Then the internal method [[DefineOwnProperty]] is called
Inside the implementation, the descriptor attributes have the following names: [[Get]] and [[Set]] .

The attributes configurable and enumerable are also available in the data descriptor:

 property = 0 object = Object.defineProperty {}, 'property' get: -> property set: (value) -> property = value configurable: on enumerable: on object.property = 1 # set object.property # 1, get 

I also want to note that the simultaneous use of data descriptors and access is not allowed:

 Object.defineProperty {}, 'property' get: -> 1 value: 1 # TypeError: property descriptors must not specify a value or be writable when a getter or setter has been specified 'value: 1" 

As in the case of Object.create () , inheritance is performed on the same principle:

 A = a: 1 b: 2 B = Object.defineProperty A, 'c' value: 3 enumerable: on for own key, value of B console.log " # {key}: # {value}" # a:1, b:2, c:3 


Object.defineProperties (object, properties)


Allows you to define new properties of the object and / or modify the attributes of existing properties. A new object is returned as a result. In other words, Object.defineProperties () does the same as Object.defineProperty () only with a lot of properties.

 object = Object.defineProperties {}, a: value: 1 enumerable: on b: value: 2 enumerable: on for own key, value of object console.log " # {key}: # {value}" # a:1, b:2 

If the names of the defined properties coincide with the inherited, then the inherited are overridden:

 A = a: 1 b: 2 object = Object.defineProperties {} a: value: 3 enumerable: on b: value: 4 enumerable: on for own key, value of object console.log " # {key}: # {value}" # a:3, b:4 

It should be remembered that redefining an accessor simply will not work:

 object = Object.defineProperty {}, 'property' get: -> 0 Object.defineProperty object, 'property' get: -> 1 object.property # 0 

Obviously, to override a property, you need to change the value of the configurable attribute:

 object = Object.defineProperty {}, 'property' get: -> 0 configurable: on Object.defineProperty object, 'property' get: -> 1 object.property # 1 

Unfortunately, IE does not support this method below version 9. However, not everything is so bad, because in the 8th version there is the Object.defineProperty () method, on the basis of which Object.defineProperties () can be implemented:

 Object.defineProperties = (object, properties) -> type = (object) -> Object::toString.call object is '[object Object]' if !type object and !type properties throw new TypeError 'Object.defineProperties(Object object, properties Object)' if !Object.defineProperty return object; for own key, value of properties Object.defineProperty object, key, value object 


Object.getOwnPropertyDescriptor (object, properties)


This method allows access to the descriptor properties.

 object = {} Object.defineProperty object, 'property' value: 1 writable: off enumerable: off configurable: on Object.getOwnPropertyDescriptor object, 'property' ### { value: 1, writable: true, enumerable: true, configurable: true } ### 

Because descriptor properties are internal properties of ECMAScript , Object.getOwnPropertyDescriptor () is the only method by which such information can be obtained. It is worth noting that Object.getOwnPropertyDescriptor () works only with its own properties:

 Object.getOwnPropertyDescriptor {}, 'valueOf' # undefined 

Because the valueOf property is inherited and is in the prototype chain:

 {}.hasOwnProperty 'valueOf' # false 'valueOf' of {} # true 

As I have already noted, the hasOwnProperty () method, in contrast to the of operator, only checks the object's own properties.

You can access the valueOf property directly, like this:

 {}.constructor::valueOf # function 

For more clarity, I would like to consider the following example:

 object = {} object.constructor::valueOf = 1 object.valueOf # 1 

At first glance, there is no difference between explicitly adding a property to an object and through a prototype object, and these record forms can replace each other. However, this is not quite true:

 object = {} object.valueOf = 1 object.constructor::valueOf = 2 object.toString # 1 

As you can see, if a property is given to an object explicitly ( own property ), then its value “overlaps” the property specified through the prototype object. More precisely, the value of the property in the prototype object does not disappear anywhere, it simply does not resolve and is always accessible directly:

 object = {} object.toString = 1 object.constructor::valueOf = 2 object.toString # 1 object.constructor::valueOf # 2 'valueOf' of object # true object.hasOwnProperty 'valueOf' # false 

In other words, if an object's property is not explicitly specified, the search continues in the prototype chain:

 object = {} object.constructor::constructor::constructor::property = 1 object.property # 1 

As a "home" assignment, I suggest you consider the following example:

 fn = (x) -> x * x fn 2 # 4 fn::constructor 4 # 8 


Object.keys (object)


Returns an array containing the names of the enumerated proper properties of the object.

Consider a typical example:

 Object.keys a: 1 b: 2 .length # 2 

Quite often Object.keys is used in conjunction with other methods of the Array object:

 object = a: 1 b: 2 Object.keys(object).filter (i) -> i if object[i] > 1 # 2 

Implementing the Object.keys () method is pretty simple:

 Object.keys = (object) -> i for own i of object 

However, I strongly recommend that you always use input argument checking.
After minor corrections, a typical implementation of Object.keys () should look something like this:

 Object.keys = (object) -> if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.keys: # {object.toString()} is not an Object" i for own i of object 

The implementation of Object.keys () according to the specification :

 Object.keys = (object) -> # 1. If the Type(O) is not Object, throw a TypeError exception if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.keys: # {object.toString()} is not an Object" # 2. Let count be the number of own enumerable properties of O count = Object.getOwnPropertyNames(object).length # 3. Let array be the result of creating a new Object as if by the expression new Array(n) # where Array is the standard built-in constructor with that name array = new Array count # 4. Let index be 0 index = 0; # 5. For each own enumerable property of O whose name String is P for own property of object if !object.propertyIsEnumerable property continue # a. Call the [[DefineOwnProperty]] internal method of array with arguments # ToString(index), the PropertyDescriptor # {[[Value]]: P, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false # b. Increment index by 1 Object.defineProperty array, index++, value: property writable: on enumerable: on configurable: on # 6. Return array array 


Object.getOwnPropertyNames (object)


Returns an array containing the names of the object's own properties.
Unlike Object.keys (object), this method does not take into account the value of the enumerable attribute:

 object = a: 1 b: 2 Object.defineProperty object, '' value: 3, enumerable: off, Object.keys(object).length # 2 Object.getOwnPropertyNames(object).length # 3 

The implementation of Object.getOwnPropertyNames () according to the specification :

 Object.getOwnPropertyNames = (object) -> # 1. If the Type(O) is not Object, throw a TypeError exception if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.getOwnPropertyNames: # {object.toString()} is not an Object" # 2. Let array be the result of creating a new Object as if by the expression new Array(n) # where Array is the standard built-in constructor with that name array = new Array # 3. Let index be 0 index = 0; # 4. For each named own property P of O for own name of object # a. Let name be the String value that is the name of P. # b. Call the [[DefineOwnProperty]] internal method of array with arguments # ToString(n), the PropertyDescriptor {[[Value]]: name, [[Writable]]: true, # [[Enumerable]]: true, [[Configurable]]: true}, and false. # c. Increment n by 1. Object.defineProperty array, index++, value: name writable: on enumerable: on configurable: on # console.log array # 5. Return array array 


Object.getPrototypeOf (object)


Returns a reference to the [[Prototype]] property of the specified object.

 object = {} Object.getPrototypeOf(object).property = 1 object.property # 1 

Method implementation:

 Object.getPrototypeOf = (object) -> if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.getPrototypeOf: # {object.toString()} is not an Object" object.__proto__ or object.constructor:: 


Object.preventExtensions (object)


Blocks an object extension.

 object = a: 1 Object.preventExtensions object object.b = 1 'b' of object # false Object.getOwnPropertyDescriptor object, 'a' # { configurable: true, enumerable: true, value: 1, writable: true } 

I want to pay special attention to the fact that an attempt to extend a blocked object using the methods: Object.defineProperty and Object.defineProperties will throw a TypeError exception!

 object = {} Object.preventExtensions object Object.defineProperty object, 'property' value: 1 # TypeError: Object.defineProperties(object, 'property', ...) is not extensible 

Also, TypeError is always thrown in strict mode:

 do -> 'use strict' object = {} Object.preventExtensions object object.property = 1 # "TypeError: object.property is not extensible 

In this case, be especially careful, because if you do not intercept TypeError , the application will stop working!


Object.isExtensible (object)


Specifies the availability of the object extension. Returns a boolean value.

 object = {} Object.preventExtensions object Object.isExtensible object # false 


Object.seal (object)


Seals the properties of the object.

 Object.seal = Object.preventExtensions + {[[Configurable]]: off} 

Consider an example:

 object = property: 1 Object.seal object delete object.property # false Object.getOwnPropertyDescriptor object, 'property' # { configurable: false, enumerable: true, value: 1, writable: true } 

Object.seal () sets the configurable attribute to false for all object properties:

 Object.getOwnPropertyDescriptor(Object.seal property: 1, 'property').configurable # false 

It is worth noting that it is not the object itself that is sealed, but only its properties:

 object = {} Object.defineProperty, 'property' value: 1 Object.seal object delete object.property # false delete object # false object.property # 1 object # Object 

As you can see, deleting an object does not work, because the delete [[Delete]] operator deletes only the properties of an object.
This happens because at the stage of translation into JavaScript code all variables are preceded by the var keyword.

To delete an object itself, you need to make it a property of a global global object:

 global.object = {} #  @object,     Object.seal object delete object object # ReferenceError: object is not defined 'object' 

However, this definition of objects is not a good practice, because object falls into the global scope:

 do -> global.object = {} object # Object 

If you want to delete an object, just give it an undefined value:

 object = {} object = undefined object # undefined 

If at some point you need to refer to this variable again, then you should use the null operator, which will signal that the variable once contained a reference to the object.

1. There is no void operator in CoffeeScript , you should use undefined instead, which is translated to void 0 .
2. There is no clear rule about deleting predefined properties.
For example, it is perfectly possible to remove the Date property of the Date object, but at the same time, you cannot delete the call method of the Function object:

  delete Date.now # true Date.now # undefined delete Function.call Function.call # [Function: call] 

In this case, it is allowed to delete the designer itself, incl. and Object ([Configurable]]: true) :

  delete Object # true typeof Object # undefined Object # ReferenceError: Object is not defined 

2. I did not consider the operator delete in more detail, because This is a fairly large topic to include in this article. If you are still interested in this question, I recommend reading the article kangax 'a Understanding delete

Besides the fact that Object.seal () prohibits the deletion of properties of an object, it also blocks the addition of new ones:

 object = {} Object.seal object object.property = 1 object.property # undefined 

Note: server implementation will throw TypeError !

However, the seal does not apply to the modification of the values ​​of the properties of the object:

 object = property: 1 Object.seal object object.property = 2 object.property # 1 

As in the case of Object.preventExtensions () , an attempt to modify the properties of an object in strict mode or using Object.defineProperty / Object.defineProperties will throw a TypeError exception!

The implementation of Object.seal () according to the specification :

 Object.seal = (object) -> # 1. If Type(O) is not Object throw a TypeError exception if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.seal: # {object} is not callable!" # 2. For each named own property name P of O, Object.getOwnPropertyNames(object).forEach (property) -> # a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P __desc__ = Object.getOwnPropertyDescriptor object, property # b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false. if __desc__.configurable is on __desc__.configurable = off # c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments Object.defineProperty object, property, __desc__ # 3. Set the [[Extensible]] internal property of O to false # 4. Return O. Object.preventExtensions object 


Object.isSealed (object)


Determines whether the object is sealed. Returns a boolean value.

 object = {} Object.seal object Object.isSealed object # true 

If an empty object is made non-expandable, it will become sealed:

 object = {} Object.preventExtensions object Object.isSealed object # true 

However, if you now add a property to an object, it will cease to be sealed:

 object = property: 1 Object.preventExtensions object Object.isSealed object # false 

The implementation of Object.isSealed () according to the specification :

 Object.isSealed = (object) -> # 1. If Type(O) is not Object throw a TypeError exception. if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.isSealed: # {object} is not callable!" # 2. For each named own property name P of O then Object.getOwnPropertyNames(object).forEach (property) -> # a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. __desc__ = Object.getOwnPropertyDescriptor object, property # b. If desc.[[Configurable]] is true, then return false. if __desc__.configurable is on return off # 3. If the [[Extensible]] internal property of O is false, then return true. # 4. Otherwise, return false. if !Object.isExtensible(object) then on else off 


Object.freeze (object)


Freezes the object.

 Object.freeze = Object.preventExtensions + Object.seal + {[[Writable]]: off} 

In other words, Object.freeze () prevents adding new properties to an object, modifying and deleting existing ones.

 object = a: 1 object.a = 0 # false    object.b = 0 # false     delete object.a # false    Object.getOwnPropertyDescriptor object, 'a' # { configurable: false, enumerable: true, value: 1, writable: false} 

Because we have already examined in detail Object.preventExtensions () and Object.seal () there is no point in repeating.
The only thing I would like to draw your attention to is the depth of the "freezing":

 object = property: internal: 1 Object.freeze object object.property = 0 # false object.property.internal = 0 # true Object.getOwnPropertyDescriptor(object.property, 'internal').writable # true 

As you can see, only the first level child properties are blocked!
Actually, there is no deep freezing method in ECMASctipt 5, nothing terrible. Let's try to implement Object.deepFreeze () by ourselves:

 Object.deepFreeze = (object) -> isObject = (value) -> Object::toString.call(value) is '[object Object]' if !isObject object throw new TypeError "Object.deepFreeze: # {object} is not callable!" for own key, value of object if isObject(value) and !Object.isFrozen value Object.deepFreeze(value) Object.freeze object object = property: internal: 1 Object.deepFreeze object Object.getOwnPropertyDescriptor(object.property, 'internal').writable # false 

The implementation of Object.freeze () according to the specification :

 Object.freeze = (object) -> # 1. If Type(O) is not Object throw a TypeError exception if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.freeze: # {object} is not callable!" # 2. For each named own property name P of O, Object.getOwnPropertyNames(object).forEach (property) -> # a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P __desc__ = Object.getOwnPropertyDescriptor object, property # b. If IsDataDescriptor(desc) is true, then # If desc.[[Writable]] is true, set desc.[[Writable]] to false if __desc__.value and __desc__.writable is on __desc__.writable = off # c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false if __desc__.configurable is on __desc__.configurable = off # d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments Object.defineProperty object, property, __desc__ # 3. Set the [[Extensible]] internal property of O to false # 4. Return O. Object.preventExtensions object 


Object.isFrozen(object)


.

 object = property: 1 Object.isFrozen object # false Object.freeze object Object.isFrozen object # true 

Object.isFrozen() :

 Object.isFrozen = (object) -> # 1. If Type(O) is not Object throw a TypeError exception. if Object::toString.call(object) is not '[object Object]' throw new TypeError "Object.isFrozen: # {object} is not callable!" # 2. For each named own property name P of O then Object.getOwnPropertyNames(object).forEach (property) -> # a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. __desc__ = Object.getOwnPropertyDescriptor object, property # b. If IsDataDescriptor(desc) is true then # i. If desc.[[Writable]] is true, return false. if __desc__.value and __desc__.writable is on return off # c. If desc.[[Configurable]] is true, then return false. if __desc__.configurable is on return off # 3. If the [[Extensible]] internal property of O is false, then return true. # 4. Otherwise, return false. if !Object.isExtensible(object) then on else off 


Object.prototype.hasOwnProperty(property)


. .

 object = property: 1 object.hasOwnProperty 'property' # true object.hasOwnProperty 'toString' # false 

, , , of , :

 object = property: 1 'property' of object # true 'toString' of object # true 

.hasOwnProperty() for-of :

 Object::inherited = 0 object = property: 1 (i for i of object) # [inherited, property] for i of object i if object.hasOwnProperty i # property 

, hasOwnProperty() .
, , hasOwnProperty :

 Object::inherited = -> object = own: 1 hasOwnProperty: -> @ for i of object i if object.hasOwnProperty i # inherited, own, hasOwnProperty 

. ?

, hasOwnProperty Object.prototype :

 Object::inherited = -> object = own: 1 hasOwnProperty: -> @ for i of object i if Object::hasOwnProperty.call object, i # own, hasOwnProperty 

.hasOwnProperty . -, , -, , .

, , .
. And since hasOwnProperty() , :

 Object.getOwnPropertyNames Object.prototype [ 'toString', 'toLocaleString', 'hasOwnProperty', 'valueOf', 'constructor', 'propertyIsEnumerable', 'isPrototypeOf', ] 

. V8 , Presto , Gecko :

  '__lookupGetter__', '__defineGetter__', '__defineSetter__', '__lookupSetter__' 

Gecko watch unwatch .

, , :

 object = {} own = Object::hasOwnProperty for i of object i if own.call object, i 

hasOwnProperty() for-of , CoffeeScript own :

 alert i for own i of object 

:

 var i, __hasProp = {}.hasOwnProperty; for (i in object) { if (!__hasProp.call(object, i)) continue; alert(i); } 

own for-of : CoffeeScript: .

Object.keys() Object.getOwnPropertyNames() , for-own-of .

Object.prototype.isPrototypeOf(object)


. .

 object = {} Object::isPrototypeOf object # true Object.isPrototypeOf object # false Function::isPrototypeOf Object # true Function::isPrototypeOf (new ->).constructor # true fn = -> instance = new fn fn::.isPrototypeOf instance # true 


Object.prototype.propertyIsEnumerable(object)


. .

 object = property: 1 object.propertyIsEnumerable 'property' # true object.propertyIsEnumerable 'toString' # false object.propertyIsEnumerable 'prototype' # false object.propertyIsEnumerable 'constructor' # false list = [''] list.propertyIsEnumerable 0 # true list.propertyIsEnumerable 'length' # false 


:


Object . ECMAScript 5 , . githab 'e

E JavaScript , .

Source: https://habr.com/ru/post/146440/


All Articles