In JavaScript, everything except the five primitive types (numbers, strings, Boolean values, null, and undefined) is an object. So, how can you continue learning if you don’t understand objects?
1. Overview An object is a composite value that aggregates many values (primitive values or other objects) together, and these values can be accessed through property names. The property name can be any string including the empty string. JavaScript objects can also be called a data structure, as we often hear "hash", "hashtable", "dictionary", "associative array". Objects in JavaScript can be divided into three categories: ①Built-in objects, such as arrays, functions, dates, etc.; ②Host object, which is defined by the host environment (such as the browser) in which the JavaScript interpreter is embedded, such as HTMLElement; ③ Custom objects, which are defined by programmers using code; The properties of an object can be divided into two categories: ① Own property: a property defined directly in an object; ②Inherited property: a property defined in the prototype object of an object (more on prototype objects below); 2. Object creation Since we are learning objects, how can we not understand how to create objects? Students who are interviewing for front-end positions may have been asked this basic question:
I have been asked this question twice. There are many sayings on the Internet about "two ways to create objects", but according to the books I read, there are three ways! Let's talk about these three methods in detail: 1. Object literal An object literal is a mapping table consisting of several name/value pairs, separated by colons, separated by commas, and enclosed in curly braces. Property names can be JavaScript identifiers or string literals, which means that the following two ways of creating an object obj are exactly the same:
2. Create an object through new The new operator is followed by a function call, the constructor, which creates and initializes a new object. For example:
We will talk about the constructor later. 3.Object.create() ECMAScript5 defines a method called Object.create(), which creates a new object. The first parameter is the prototype object of this object (I don’t think I’ve explained the prototype object yet… I’ll explain it below), and the second optional parameter is used to further describe the properties of the object. I’ll explain the second parameter below (because this third method is defined in ECMAScript5, so people often talk about the two ways to create objects before? I think this is the reason). This method is very simple to use:
The following three are exactly the same:
To explain why these three methods are exactly the same, let's first explain the prototype object in JavaScript (sorry, I kept you waiting for a long time!). I remember a great god said:
JavaScript, an object-oriented programming language, has no classes!!! So, how does it implement inheritance? That's right, it's through the prototype object. Basically, every JavaScript object (except null) is associated with another object, and the "other" object is the so-called prototype object (the prototype object can also be simply called prototype, which is not as complicated as imagined, it is just an object). Every object inherits properties from the prototype object, and the value of an object's prototype property (this property is automatically generated by default when the object is created and does not need to be explicitly customized) is the prototype object of this object, that is, obj.prototype is the prototype object of the object obj. Let's talk about prototype objects first. Back to the above question, with the understanding of prototype objects, the following are the JavaScript language regulations that do not need too much explanation: ① The prototype object of all objects created directly by objects is the Object.prototype object; ②The prototype object of the object created by the keyword new and the constructor is the value of the prototype property of the constructor, so the prototype of the object created by the constructor Object is Object.prototype; Now the meaning of the first parameter of the third method Object.create() to create objects has also been added. 3. Query and set properties Learning how to create objects is not enough, because objects can only be useful if they have some properties! So, continue learning about the properties of objects! You can use the dot (.) or square bracket ([]) operator to get and set the value of a property. For the dot (.), the right side must be an identifier named after the property name (note: JavaScript language identifiers have their own legal rules, which are different from quoted strings); for square brackets ([]), the square brackets must be a string expression (string variables are of course OK, and other values that can be converted to strings, such as numbers, are also OK), and this string is the name of the property. As shown in the following example:
As mentioned in the overview, JavaScript objects have "own properties" and "inherited properties". When querying the property x of object obj, it will first look for x in the object obj's own properties. If not, it will look for the property x in the prototype object obj.prototype of object obj. If not, it will then look for the property x in the prototype object obj.prototype.prototype of object obj.prototype, and so on until x is found or the prototype object found is an undefined object. As you can see, an object inherits many prototype objects, and these prototype objects form a "chain", which is what we usually call the "prototype chain". This kind of inheritance is also called "prototypal inheritance" in JavaScript. When object o queries a certain property, it will search step by step along the prototype chain as mentioned above. However, when it sets the value of a certain property, it will only modify its own properties (if the object does not have this property, it will add this property and assign a value), and will not modify the properties of other objects on the prototype chain. 4. Accessor property getters and setters What we have said above are all very common object properties, which are called "data properties". Data properties have only one simple value. However, in ECMAScript 5, property values can be replaced by one or two methods, which are getters and setters. Properties defined with getters and setters are called "accessor properties". When the program queries the value of an accessor property, JavaScript calls the getter method (without parameters). The return value of this method is the value of the property access expression. When the program sets the value of an accessor property, JavaScript calls the setter method and passes the value on the right side of the assignment expression as a parameter to the setter. If a property has both a getter and a setter method, it is a read/write property; if it only has a getter method, it is a read-only property, and assigning a value to a read-only property will not result in an error, but it will not succeed; if it only has a setter method, it is a write-only property, and reading a write-only property always returns undefined. Let's take a look at a practical example:
As written in the example, the accessor property defines one or two functions with the same name as the property. This function definition does not use the function keyword, but uses get and set, and does not use a colon to separate the property name from the function body. In contrast, the print property below is a function method. Note: The use of the this keyword in the getter and setter here, JavaScript calls these functions as object methods, that is, this in the function body refers to this object. Let's take a look at the example running results: Just like the console output, r and theta are just value attributes like x and y, and print is a method attribute. Although this accessor added by ECMAScript 5 is more complicated than ordinary properties, it also makes the operation of object property key-value pairs more rigorous. 5. Delete attributes When programmers write code, they usually implement the functions of adding, deleting, modifying and checking. We have already talked about adding, modifying and checking, and now let’s talk about deleting! The delete operator can delete the properties of an object. Its operand should be a property access expression. However, delete only disconnects the property from the host object, and does not operate on the properties in the property:
After executing this code, the value of bx is still 1. Since the reference to the deleted attribute still exists, this kind of imprecise code may cause memory leaks. Therefore, when destroying the object, it is necessary to traverse the attributes in the attribute and delete them one by one. When the delete expression returns true: ① When the deletion is successful or has no side effects (such as deleting a non-existent attribute); ②If delete is not followed by an attribute access expression;
When the delete expression returns false: ① When deleting a property whose configurability (configurability is a characteristic of a property, which will be discussed below) is false;
6. Characteristics of attributes The configurability of properties has been mentioned above. Since the detection properties and enumeration properties to be discussed below will also use the concepts of property characteristics, let's talk about the properties in detail now! In addition to names and values, properties also contain three characteristics that indicate they are writable, enumerable, and configurable. These characteristics cannot be set in ECMAScript 3. All properties created by ECMAScript 3 programs are writable, enumerable, and configurable, and these characteristics cannot be modified. ECMAScript 5 provides APIs for querying and setting these property characteristics. These APIs are very useful for library developers because: ① You can add methods to prototype objects through these APIs and set them to be non-enumerable, which makes them more like built-in methods; ② You can use these APIs to define properties that cannot be modified or deleted for an object, thereby "locking" the object; Here we regard the getter and setter methods of accessor properties as the characteristics of the property. According to this logic, we can also regard the value of the property as the characteristic of the property. Therefore, it can be considered that the property contains a name and four characteristics. The four characteristics of a data property are its value, writability, enumerability, and configurability. Accessor properties do not have value characteristics and writability. Their writability is determined by whether the setter method exists. Therefore, the four characteristics of accessor properties are read (get), write (set), enumerability, and configurability. In order to implement the query and setting operations of property characteristics, ECMAScript 5 defines an object called "property descriptor", which represents the four characteristics. The properties of the descriptor object have the same name as the property characteristics they describe. Therefore, the properties of the descriptor object of the data property are value, writable, enumerable, and configurable. The descriptor object of the accessor property uses get and set properties instead of value and writable. Among them, writable, enumerable, and configurable are all Boolean values, and of course, get and set properties are function values. The property descriptor of a specific property of an object can be obtained by calling Object.getOwnPropertyDescriptor(): As you can see from the function name, Object.getOwnPropertyDescriptor() can only get the descriptor of its own properties. It returns undefined for inherited properties and non-existent properties. To get the characteristics of inherited properties, you need to traverse the prototype chain (don't know how to traverse the prototype chain? Don't worry, I'll explain it below). To set the characteristics of a property, or to give a newly created property certain characteristics, you need to call Object.defineProperty(), passing in the object to be modified, the name of the property to be created or modified, and a property descriptor object: You can see: ① The property descriptor object passed into Object.defineProperty() does not have to contain all 4 properties; ②Writability controls the modification of attribute values; ③ Enumerability controls whether the attribute is enumerable (enumeration attributes, which will be discussed below); ④Configurability controls the modification of other features (including whether the attributes mentioned above can be deleted); If you want to modify or create multiple properties at the same time, you need to use Object.defineProperties(). The first parameter is the object to be modified, and the second parameter is a mapping table that contains the names of the properties to be created or modified, as well as their property descriptors, for example:
I believe you have also seen from the examples: Object.defineProperty() and Object.defineProperties() both return the modified object. Earlier, we said that getter and setter accessor properties use object literal syntax to define accessor properties for new objects, but you cannot query the getter and setter methods of properties or add new accessor properties to existing objects. In ECMAScript 5, you can use Object.getOwnPropertyDescriptor() and Object.defineProperty() to complete these tasks! But before ECMAScript 5, most browsers (except IE) already supported the get and set writing in object literal syntax. So these browsers also provide non-standard old-fashioned APIs for querying and setting getters and setters. These APIs consist of 4 methods, and all objects have these methods. __lookupGetter__() and __lookupSetter__() are used to return the getter and setter methods of a named property. __defineGetter__() and __defineSetter__() are used to define getters and setters. These four methods are prefixed with two underscores and suffixed with two underscores to indicate that they are non-standard methods. Here are their uses: #p# 7. Detection attributes JavaScript objects can be seen as a collection of attributes, so sometimes we need to determine whether a certain attribute exists in an object. This is what we will talk about next, detecting attributes. There are also three ways to detect the properties of an object. Let's talk about their functions and differences in detail! 1.in operator The in operator takes a property name (string) on the left and an object on the right. It returns true if the object's own or inherited properties contain this property, otherwise it returns false. For the purpose of experiment, we first add an enumerable property m and a non-enumerable property n to the object Object.prototype; then, define two enumerable properties x and a non-enumerable property y for the object obj, and the object obj is created in the form of an object literal, inheriting Object.prototype. Let's look at the example below: From the running results, we can see that the left side of the in operator is the property name (string), and the right side is the object. If the object's own properties or inherited properties (regardless of whether these properties are enumerable) contain this property, true is returned, otherwise false is returned. 2. hasOwnProperty() The hasOwnProperty() method of an object is used to detect whether the given name is an object's own property (regardless of whether these properties are enumerable). It will return false for inherited properties. Let's look at the example below: 3.propertyIsEnumerable() propertyIsEnumerable() is an enhanced version of hasOwnProperty(). It returns true only when it detects that it is an owned property and the enumerability of this property is true. Or an example: 8. Enumeration attributes Compared with detection attributes, we often use enumeration attributes. We usually use for/in loops to enumerate attributes. It can traverse all enumerable own attributes and inherited attributes in the object in the loop body and assign the attribute name to the loop variable. Continuing with the example: I used to think that the for/in loop had a lot to do with the in operator, but now it seems that their rules are different! Of course, if you don't want to traverse the inherited properties here, then add a hasOwnProperty() check in the for/in loop:
In addition to the for/in loop, ECMAScript 5 defines two functions that can enumerate property names: ①Object.getOwnpropertyNames(), which returns the names of all the object's own properties, whether enumerable or not; ②Object.keys(), which returns the names of the enumerable own properties in the object; Or an example: 9. Three special properties of objects Each object has a prototype, a class, and an extensible attribute associated with it. These three are the special properties of the object (they are just the properties of the object, not as complicated as you might think). 1. Prototype properties As mentioned earlier, the prototype property of an object is used to inherit properties (a bit confusing...). This property is so important that we often call "o's prototype property" directly "o's prototype". The prototype property is set at the beginning of the instance creation (that is, the value of this property is automatically set by JavaScript by default, and we will talk about how to set it manually later). As mentioned earlier: ① Objects created directly by object use Object.prototype as their prototype; ②Objects created by new+constructor use the prototype property of the constructor as their prototype; ③Objects created by Object.create() use the first parameter (if this parameter is null, the object prototype property value is undefined; if this parameter is undefined, an error will be reported: Uncaught TypeError: Object prototype may only be an Object or null: undefined) as their prototype; So, how do you query the prototype property of an object? In ECMAScript 5, you can query its prototype by passing the object as a parameter to Object.getPrototypeOf(), for example: However, in ECMAScript 3, there is no Object.getPrototypeOf() function, but the expression obj.constructor.prototype is often used to detect the prototype of an object, because each object has a constructor property that represents the constructor of this object: ① The constructor property of the object created by the object literal points to the constructor Object(); ②The constructor property of the object created by new+constructor points to the constructor; ③The constructor property of the object created by Object.create() points to the same as the constructor property of its prototype object; To check whether an object is a prototype of another object (or is in the prototype chain), you can use the isPrototypeOf() method. For example: There is also a non-standard but many browsers have implemented the object property __proto__ (also starts and ends with two underscores to indicate that it is non-standard), which is used to directly query/set the prototype of the object. 2. Class attributes The class attribute of an object is a string that represents the type information of the object. Neither ECMAScript 3 nor ECMAScript 5 provides a method to set this property, and there is only an indirect way to query it. The default toString() method (inherited from Object.prototype) returns a string in this format: [object class]. Therefore, to obtain the class of an object, you can call the toString() method of the object and then extract the characters from the 8th to the second to last position of the returned string. However, many objects inherit and override the toString() method (for example: Array, Date, etc.). In order to call the correct toString() version, the Function.call() method must be called indirectly. The following code can return the class of any object passed to it:
The classof() function can be passed any type of parameter. Here is an example: Summary: From the running results, we can see that the class attributes of objects created in three ways are all 'Object'. 3. Scalability The extensibility of an object indicates whether new properties can be added to the object. All built-in objects and custom objects are explicitly extensible (unless they are converted to non-extensible). The extensibility of the host object is defined by the JavaScript engine. ECMAScript 5 defines functions for querying and setting object extensibility: ① (Query) Determine whether the object is extensible by passing it into Object.isExtensible(). ② (Settings) If you want to convert an object to non-extensible, you need to call Object.preventExtensions() and pass the object to be converted as a parameter. Note: a. Once an object is converted to non-extensible, it cannot be converted back to extensible; b.preventExtensions() only affects the extensibility of the object itself. If you add properties to the prototype of a non-extensible object, the non-extensible object will also inherit these new properties. Furthermore, Object.seal() is similar to Object.preventExtensions(). In addition to setting an object to be non-extensible, it can also set all of an object's own properties to be non-configurable. Objects that have been sealed cannot be unsealed. You can use Object.isSealed() to check whether an object is sealed. Going a step further, Object.freeze() will lock the object more strictly - "freeze" (frozen). In addition to setting the object to be non-extensible and setting its properties to be non-configurable, you can also set all of its own data properties to read-only (if the object's accessor properties have setter methods, the accessor properties will not be affected and can still be called by assigning values to the properties). Use Object.isFrozen() to detect whether the object is frozen. Summary: Object.preventExtensions(), Object.seal(), and Object.freeze() all return the passed object, that is, they can be called in a nested manner:
In this statement, the Object.create() function is used to pass in two parameters. The first parameter is the prototype object of the created object, and the second parameter is the attribute defined directly when the object is created, and the characteristics of the attribute are defined along with it. 10. Object Serialization We have already talked about the properties of objects and their characteristics. There is still a lot to cover, and I wonder if you are already dizzy. However, the following is a more relaxing topic! Object serialization refers to converting the state of an object into a string, and also restoring a string into an object. ECMAScript 5 provides built-in functions JSON.stringify() and JSON.parse() to serialize and restore objects. These methods all use JSON as the data exchange format. The full name of JSON is "JavaScript Object Notation". Its syntax is very similar to the syntax of JavaScript objects and array literals: Among them, the last jsonObj is a deep copy of obj (for what is a deep copy and what is a shallow copy, please refer to: http://www.zhihu.com/question/23031215, the second answer). JSON syntax is a subset of JavaScript, and it cannot represent all values in JavaScript. It supports objects, arrays, strings, infinite numbers, true, false, and null, and they can be serialized and restored. Note: ①The serialization result of NaN, Infinity and -Infinity is null; ②JSON.stringify() can only serialize the enumerable properties of an object; ③The serialized result of the date object is an ISO format date string (refer to the Date.toJSON() function), but JSON.parse() still retains their string form and cannot restore them to the original date object; ④ Functions, RegExp, Error objects and undefined values cannot be serialized and restored; Of course, both JSON.stringify() and JSON.parse() can accept a second optional parameter to customize the serialization or restoration operation by passing in a list of properties to be serialized or restored. We will discuss this in detail later. |
<<: Ruan Yifeng: Why is the memory address of the master boot record 0x7C00?
>>: Tencent technical tips! How to make a terrifying HTML5 page
Yesterday, Meizu MX4 was officially released. Tog...
The dishwashing tool I used when I was a kid. Can...
A year later, huge losses hit Japanese home appli...
[Summer 2021] Senior high school Chinese language...
2019 was a "winter period" for the educ...
[[161924]] Jarvis, the artificial intelligence bu...
As the iPhone throttling incident ferments around...
This article hopes to help entry-level product ma...
The winning works of the 2023 "China Science...
1.16 million mobile phones and a total sales volu...
Introduction to training course content: The cours...
199IT original compilation According to the lates...
Question 1: I don’t know where to tap into the iO...
Produced by: Science Popularization China Author:...
Let’s get into today’s topic, a sigh from the bot...