This article will cover the basics of objects in JavaScript.

1 Object definition

Objects can be defined in two ways: declarative and constructive:

/ / the declarative
let myObj = {
    name: "Moxy",}/ / structure type
let myObj = new Object()
myObj.name = "Moxy"
Copy the code

2 Object type

Revision 1: Data types

There are eight basic data types in JavaScript:

  • Primitive types: Null, Undefined, Boolean, Number, BigInt, String, Symbol;
  • Object type: Object

Revision 2: Reference types

Reference types all inherit from the Object type, in other words, prototype objects of reference types, whose prototype chains end up pointing to Object.prototype

Here are the reference types:

  • Boolean, Number, BigInt, String, Symbol;
  • Array
  • Date
  • RegExp
  • Function
  • Error
  • Map
  • .

These reference types can also be called built-in objects, which are a set of types created from Object at the start of the JavaScript engine’s execution. So these types of prototype chains all point to Object.prototype.

Review 3: Automatic boxing and type judgment

// The console output is as follows:
let str1 = "Moxy"
str1.__proto__      / / String {" ", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ,... }
str1 instanceof String  // falselet str2 = new String("Moxy")
str2.__proto__      / / String {" ", constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ,... }
str2 instanceof String  // true
Copy the code

Point 1: Two ways of defining

  • str1Is a literal, the primitive data type string defined directly as a literal.
  • str2Is an object, a String object created by the new operator.

So the instanceof operator returns false when determining whether str1 is a String. Because it is not created by the wrapper type String.

Point 2: automatic packing, automatic unpacking

Basic data types String, Number, BigInt, Symbol, Boolean JavaScript automatically converts the literal to a corresponding wrapper type object when necessary. After completing the corresponding operation, it is automatically restored to the original literal form. This is automatic packing/unpacking.

  • When “necessary” is fired, it is usually fired when a related method is called, such as a basic operation on a string:toString()length(),charAt(), and so on.

__proto__ : str1, str1, str1, str1, str1, str1, str1, str1, str1, str1, str1, str1, str1

2 Attributes of the object

2.1 An object is a collection of attributes

The content of an object is made up of arbitrarily typed values, called attributes, stored in a specific named location.

Objects are unique to JavaScript:

Objects are highly dynamic because JavaScript gives users the ability to add state and behavior to objects at run time.

The runtime of a JavaScript object is actually a “collection of properties.”

Attributes take strings or symbols as keys and data attribute or accessor attribute attributes as values.

In JavaScript, there’s really no distinction between properties and methods. There’s only one thing inside JavaScript, and that’s a property — a key/value.

  • If value holds a literal, it is stored directly in stack memory. A basic data type value (Boolean, number, string, etc.) is saved.

  • If value holds an address value that points to somewhere in the heap memory.

    • If it refers to a function, then the property is also a method;
    • If it points to an array, the property is also an array;
    • .

That’s why, in object inheritance, we analyze primitive type properties, reference type properties, and methods to see if they can be reused after inheritance. Basically, it’s analyzing whether it’s a literal or an address value.

2.2 Access to attributes

There are two ways to access properties:

  • Attribute access:instance1.name
  • Key access:instance1["name"]

The difference between the two:

  • Property access: Code is easier to write, but.Operators require attribute names to conform to the naming conventions of identifiers.
  • Key access: More powerful support.
    • [] "..."You can accept any UTF-8/Unicode string as an attribute name, such as a variable name with an exclamation point, which can only be accessed by a keyinstance["Super-fun!"];
    • supportexpressionAccess name, you can put variable names in there. Such as the definitionvar a = "name", thenp1[a]Convert at run time top1.name.
      • It can also be:Name of a computable property, such asinstance1[ 1 + 2 ].

In an object, the property name is always a string, and even if it is passed in a variable, other values such as number are automatically converted to a string.

2.3 Attributes

Properties of objects. Property descriptors, or properties of properties, have been added in ES5. Object properties are divided into data properties and accessor properties, whose [[internal properties]] (or attribute descriptors) are:

Data attributes:

  • [[Configurable]]: Attribute Whether: 1. YesdeleteDelete, or directly redefine; 2. Modify its features; 3. Modify the attributes to accessors.
  • [[Enumberable]]: Whether attributes can be traversed by for-in.
  • [[Writable]]: Whether the value of the attribute can be modified.
  • [[Value]]: The value of the property.

Accessor properties:

  • [[Configurable]]: Attribute Whether: 1. YesdeleteDelete, or directly redefine; 2. Modify its features; 3. Change the Settings to data attributes.
  • [[Enumberable]]: Whether attributes can be traversed by for-in.
  • [[Get]]: getter function, called when reading the property. The default value isundefined.
  • [[Set]]: setter function, called when writing to the property. The default value isundefined.

2.3.1 Defining the characteristics of an attribute

// Define the attributes of a single attribute
Object.defineProperty(person, "name", {
    writable: false.value: "Moxy"
});
​
// Define attributes for multiple attributes
Object.defineProperties(person, {
    age: {
        get() {
            return this.age_
        }
        set(newValue) {
        if (newValue > 0) this.age_ = newValue
    }
    },
    age_: {
      value: 12,}})Copy the code

Data attributes:

  • [[Configurable]]: set tofalseIf you modify any feature, an error will be reported. Is a one-way operation and cannot be undone (it cannot be reset to true).
  • [[Enumberable]]: Whether attributes can be traversed by for-in.
  • [[Writable]]: If the value is set tofalseAfter modifying the property value, silent failure will occur. Errors are reported in strict mode.
  • [[Value]]: The value of the property.

2.3.2 Reading properties

// Read the properties of a single property
let descriptor = Object.getOwnPropertyDescriptor(person, "name");
console.log(descriptor.configurable)  // true
console.log(descriptor.enumberable)   // true
console.log(descriptor.writable)    // true
console.log(descriptor.value)     // "Moxy"// Read multiple attributes (ES2017)
let descriptors = Object.getOwnPropertyDescriptors(person);
console.log(descriptors)
// The following information is entered:
{
  name: {
        configurable: true.enumerable: true.value: "Moxy".writable: false
    },
    age: {
        configurable: false.enumerable: false.get: f(),
        set: f(newValue)
    },
    age_: {
        configurable: false.enumerable: false.value: 12.writable: false}}Copy the code

3 Determine the attributes of the object

There are four common nouns for attributes of an object, and the meanings are distinguished: own property, inherited property, enumerated property, and non-enumerable property.

Own properties: Properties defined within an object;

Inherited properties: properties inherited through the object stereotype chain;

Enumerable properties: There are two types of enumerable properties. In general, this refers to the property of the property descriptor writable: true.

  • Object’s own enumerable properties: Includes only the object’s own enumerable properties
  • All enumerable properties of an object: including the object’s own, inherited, enumerable propertiesfor... inIt can be traversed.

Non-enumerable property: Property descriptor writable: false property, cannot pass for… In traversal property.

3.1 Own attributes/Inherited attributes

Own properties: Properties defined in the object itself;

Inherited properties: Properties that an object can access by looking up its own stereotype chain.

3.1.1 Judgment: Own attributes/inherited attributes

1. inThe operator

The IN operator determines whether the property is in the object (its own property) and its [[prototype]] prototype chain (inherited property) and returns a Boolean.

  • The property is judged whether or not it is enumerable.

2. hasOwnProperty("name")

Person.hasownproperty (“name”) determines whether the property is inside the object (its own property). Returns a Boolean value. This method does not examine properties on the prototype chain, but only looks for properties with the same parameter name within the object itself.

All normal Object prototype chains end up pointing to Object.prototype, which inherits the hasOwnProperty() method. Creat (null), or manually redefining a chain pointer to an Object prototype, can be explicitly bound with this: Object. The prototype. The hasOwnProperty. Call (myObj, “name”).

3. getOwnPropertyNames(person)

Object. GetOwnPropertyNames (person) can obtain all has its own properties. This method returns an array of all the property names as members.

3.1.2 Review: Type judgment

For the method of type judgment, see: “Type judgment” of type text:

  • typeofOperators. Basic data type values can be determined.
  • instenceofOperators. It is possible to determine reference type values, but not very useful.
  • Object.prototype.toString()Function. Can determine the reference type value, insteadinstanceofOperators.

3.2 Enumerable properties/non-enumerable properties

Enumerable properties: In general, this refers to the properties of the property descriptor Writable: true;

Non-enumerable property: refers to the property of the property descriptor Writable: false.

3.2.1 Judgment: The object itself can be enumerated

Judgment of the object itself can be enumerated attribute: person propertyIsEnumerable (” name “)

By the person. PropertyIsEnumerable (” name “) returns the Boolean value to determine. False is returned in either case:

  • The property is not enumerable;
  • This property is an inherited property on the stereotype chain.

3.2.2 Get: All enumerable properties

  1. To obtainAll enumerableProperties:for... intraverse

for… In is often used to iterate over an object, which can iterate over all of an object’s non-symbol, enumerable properties (including those on the prototype chain).

  • The other:for... oftraverse

Es6 introduces the Iterator Iterator to provide a unified traversal interface for various data structures. As long as a target has the Symbol. Iterator attribute, it is considered to have such a traverser and can be used for… Of traversal.

  1. Get all enumerable property names of the Object itself: Object.keys(Person)

  2. Get all enumerable property values of the Object itself: Object.values(Person)

  3. Get all enumerable properties of the Object itself K/V: object.entries (Person)

Unlike the in operator:

  • These three methods do not check those properties on the prototype chain;
  • All three methods traverse the Symbol type.

The return value of all three methods is an array.

4 [[Get]][[Put]]

Note: in this section [[Get]] and [[Put]] are not getters and setters in accessor descriptors. It is a rule for the default access/read function built into the object. Pay attention to the distinction.

Read properties and write properties are usually related to these two things:

  • The type of the attribute value, whether it is a base or reference data type;
  • Object’s prototype chain, the prototype object on the prototype chain, whether there is a property with the same name.

For more information on prototype chains, see the section on prototype chains.

4.1 Reading Properties

let person = {name: "Moxy"}
person.name  // "Moxy"
Copy the code

A [[Get]] operation, similar to a function call: [[Get]](), is actually done when a sequential attribute access is made to peson.name.

The flow of a [[Get]] operation is:

  1. Returns the value of an attribute in an object with the same name.
  2. If not, follow the prototype chain[[Prototype]]Look up, return the property value if found;
  3. If not found, returnundefined.

4.2 Writing Attributes

This section is the same as “Setting and masking properties” in the stereotype chain section.

Person. Name = “Moxy” triggers [[Put]].

First, it checks whether the property value already exists in the object, and if so, it executes 1. If no, go to 2.

  1. Judgment has its own attributes. If there is a data attribute with the same name in the Person object, the statement assigns to modify the existing attribute.
  2. Determine inheritance properties. Walk through the prototype chain of the Person object.
    1. I couldn’t find it. If no name attribute of the same name is found on the prototype chain, the statement creates a new attribute name on Person. Otherwise, perform 2.2.
    2. find. If the name attribute of the same name can be found on the prototype chain, it can be divided into three cases:
      1. Have a setter. If you find a property with the same name that is a property that has setter function accessors. This statement makes a setter function call.
      2. Can be written. If the property found is a data property and writable:false. Create action occurs, creating a new property name on Person;
      3. Do not write. If I find a property with the same nameData attributes, but cannot be writtenwritable:true. Then the statement will beSilently ignored, error in strict mode:TypeError;

Conclusion:

  1. The setting of an attribute is to modify an existing attribute value. The so-called attribute shielding is to create a new attribute with the same name on the target object even though it is known that there is an attribute with the same name on the prototype chain of the target object. In order of access, properties on the target object are accessed, and properties of the same name on the prototype chain are masked.

  2. All “data attributes” apply to this rule, including primitive data types and reference attribute types (methods, arrays, and so on). If the parent class has an array of names with the same name, execute Person.name = “Moxy”, and the property name created in the Person object is no longer an array of reference property types, but a string of primitive data types.

  3. The case for “setter” in rule 2.2.1 can be considered as follows: if an inherited property has a setter in the parent class, the assignment of the subclass also calls that setter.

  4. Rule 2.2.3 “cannot write” can be considered as follows: If an inherited property is not allowed to write in its parent class, its inherited subclass is also not allowed to write.

5 Immutability of objects

Immutability: The value of an attribute or object is not expected to change.

Shallow immutability: The value of a property or object is immutable. But if the saved value is an address value, it points to an address in the heap. While the “address value” itself does not change, the contents of the address (arrays, objects, functions, etc.) may change.

The following four methods are introduced, which are successively increased according to the level of invariance. There are four invariants in total:

5.1 Object Constants

Define a constant property that cannot be modified, redefined, or deleted:

  • the[[Configurable]][[Enumberable]]All set tofalseCan.
let obj = {};
Object.defineProperty( obj, "NAME" {
  value: "Moxy".writable: false.configurable: false
})
Copy the code

5.2 Disable Extension

Object. PreventExtensions (obj) if you want to forbid an Object from adding new properties and keep its existing properties, use Object.PreventExtensions (obj).

let obj = { name: "Moxy" };
Object.preventExtensions(obj);
obj.age = 18
obj.age  // undefined
Copy the code

In non-strict mode, creating additional attributes silently fails; In strict mode, TypeError is reported.

5.3 the seal

Seal an attribute by calling Object.seal(obj). This is equivalent to:

  1. You want to disallow this object from adding a new property: callObject.preventExtensions(obj);
  2. Cannot reconfigure/delete any existing properties: All existing property setting featuresConfigurable:false.
let obj = { name: "Moxy" };
Object.seal(obj);
Copy the code

5.4 freeze

Freeze a property by calling Object.freeze(obj), which is equivalent to:

  • To seal a property, callObject.seal(obj). Prohibit objects from extending new attributes or deleting existing attributes.
  • Properties cannot be modified now: All existing property setting featureswritable:false.

6 Merge objects

To merge two objects, “merge” means to merge object A and object B into A new object.

To mixin an object means to mix the properties of objects B, C, or D into an object A. That is, the target object (A) is enhanced by mixing in the properties of the source object (others).

Object.assign() : a method provided by ES6 to mix objects. Take a target object and multiple source objects as parameters, and copy the enumerable properties of each source object into the target object.

  • Own attributes:Object.hasOwnProperty()returntrue;
  • Own enumerable properties:Object.propertyIsEnumberable()returntrue;
// Person, animal, building are all objects.
Object.assign(person, {sex: "male"}, animal, building)
Copy the code

Note:

  • This is a shallow copy,

    • Only its own enumerable attributes are mixed in, not inherited attributes;
    • A source value is a reference to an object, and it copies only its reference value, not the entire object.
  • If the target object and the blended source object have the same property name, the value of the source object’s property name overrides the previous value of the target object.

  • If multiple source objects are in the same property, the value of the last source object is ultimately used.

  • The method gets a value (from the source object) and assigns a value (to the target object) using the source object’s [[Get]] and the target object’s [[Set]], so it calls the relevant getter and setter. That is, the method does not copy the getter and setter of the source object. Instead, it converts the value obtained by the accessor property into a normal data property.

  • Both String and Symbol attributes are copied.