Home  >  Article  >  Web Front-end  >  Detailed explanation of JavaScript basic objects (organized and shared)

Detailed explanation of JavaScript basic objects (organized and shared)

WBOY
WBOYforward
2021-12-20 15:06:541959browse

This article brings you relevant knowledge about objects in JavaScript. Objects in JavaScript are also variables, but objects contain many values. I hope it will be helpful to you after reading this article.

Detailed explanation of JavaScript basic objects (organized and shared)

1. The basis of objects

1.1 Type

JavaScript has six main language types:

string, number, boolean, undefined, null, object

Basic types: string, number, boolean, undefined, null; the basic types themselves are not objects.

null

But null is sometimes regarded as an object, and typeof null will return object. In fact, null is a basic type. The reason is that different objects are represented as binary at the bottom level. In JavaScript, if the first three digits of the binary number are 0, it will be judged as the object type, and null means all 0s, so typeof will return object.

Special object subtypes

Array

Array is also a type of object with some additional behaviors. The organization of arrays is more complex than ordinary objects.

Function

Functions are essentially the same as ordinary functions, except that they can be called, so you can operate functions in the same way as objects.

1.2 Built-in Object

String
Number
Date
Boolean
Object
Function
Array

1.3 Content

.a is called attribute access, and ['a'] is called operator access.

//对象中的属性名始终是字符串
myobj={}

myobj[myobj]='bar'//赋值

myobj['[object object]'] //'bar'

1.4 Calculable attribute names

es6 Add computable attribute names, you can use [] in text form to wrap an expression as the attribute name

var perfix = 'foo'

var myobj={
    [perfix + 'bar'] :'hello'
}

myobj['foobar']//hello

1.5 Attribute descriptor

Starting from es5, all attributes have attribute descriptors. For example, you can directly determine whether the attribute is readable and writable.

/*
 * 重要函数:
 * Object.getOwnPropertyDescriptor(..) //获取属性描述符
 * Object.defineProperty(..) //设置属性描述符
 */
 writeble(可读性)
 configurable(可配置性)
 enumerable (可枚举性)

1.6 Traversal

for in

for in can be used to traverse the enumerable attribute list of the object (including the [[Prototype]] chain), and you need to manually obtain the attribute value . Can traverse arrays and ordinary objects

for of

es6 is new and can be used to traverse the attribute values ​​​​of arrays. The for of loop will first request an iterator object from the accessed object, and then Iterate through all return values ​​by calling the next() method of the iterator object.
Arrays have built-in @@iterators,

how does for of work?

var arr = [1, 2, 3]
var it = arr[Symbol.iterator]()//迭代器对象
console.log(it.next());//{value: 1, done: false}
console.log(it.next());//{value: 2, done: false}
console.log(it.next());//{value: 3, done: false}
console.log(it.next());//{value: undefined, done: true}

/*
 * 用es6 的Symbol.iterator 来获取对象的迭代器内部属性。
 * @@iterator本身并不是一个迭代器对象,而是一个返回迭代器对象的函数。
 */

How does an object have a built-in @@iterator to traverse the values ​​of attributes?

Because the object does not have a built-in @@iterator, the for...of traversal cannot be automatically completed. However, you can define @@iterator for any object you want to traverse, for example:

  var obj={
      a:1,b:2
  }
  
   Object.defineProperty(obj, Symbol.iterator, {
        enumerable: false,
        writable: false,
        configurable: true,
        value: function () {
            var self = this
            var idx = 0
            var ks = Object.keys(self)
            return {
                next: function () {
                    return {
                        value: self[ks[idx++]],
                        done: (idx > ks.length)
                    }
                }
            }
        }
    })
    
    //手动遍历
    var it = obj[Symbol.iterator]()//迭代器对象
    console.log(it.next());//{value: 1, done: false}
    console.log(it.next());//{value: 2, done: false}
    console.log(it.next());//{value: undefined, done: true}

   //for of 遍历
    for (const v of obj) {
        console.log(v);
    }
    //2
    //3

Other array traversal functions

 /*
 forEach:会遍历所有并忽略返回值
 some:会一直运行到回调函数返回 true(或者"真"值)
 every:会一直运行到回调函数返回 false(或者"假"值)
 map:
 filter:返回满足条件的值
 reduce:
 some和every 和for的break语句类似,会提前终止遍历
 */

2. Mixed class objects

Interview questions

1. Deep copy and shallow copy of objects

Related knowledge

Basic types and reference types

As mentioned above, the main language types of JavaScript There are six types: string, number, boolean, null, undefined, and object; the first five are basic types, and the last object is a reference type.

The storage methods of JavaScript variables: stack and heap

Stack: automatically allocates memory space and is automatically released by the system. It stores basic type values ​​and reference types. The address of

Heap: dynamically allocated memory, the size is variable and will not be automatically released. Reference type values ​​are stored in it

The biggest difference between basic types and reference types is the difference between passing by value and passing by address

Basic types use value passing; reference types use address (pointer) passing. Assign the address stored in stack memory to the received variable.

What are shallow copy and deep copy?

Shallow copy: A shallow copy of an object will copy the 'main' object, but will not copy the objects in the object. The 'inner object' is shared between the original object and its copy.

Deep copy: A deep copy of an object not only copies each attribute of the original object out one by one, but also deeply copies the objects contained in each attribute of the original object. The method is recursively copied to the new object, so modifications to one object will not affect the other object.

For example:

var anotherObject={
    b:"b"
}

var anotherArray=[]

var myObject={
    a:'a',
    b:anotherObject, //引用,不是副本
    c:anotherArray //另外一个引用
}

anotherArray.push(anotherObject,myObject)

/*
  如何准确的复制 myObject?
 浅复制 myObject,就是复制出 新对象中的 a 的值会复制出对象中a 的值,也就是 'a',
 但是对象中的 b、c两个属性其实只是三个引用,新对象的b、c属性和旧对象的是一样的。
 
 深复制 myObject,除了复制 myObject 以外还会复制 anotherObject 和 anotherArray。
 但是这里深复制 myObject会出现一个问题,anotherArray 引用 anotherObject 和 myObject,
 所以又需要复制 myObject,这样就会由于循环引用导致死循环。
 后面会介绍如何处理这种情况。
*/

How to implement shallow copy

object

object.assign(), spread operator (…)

var obj1 = {x: 1, y: 2}
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 1, y: 2}
obj2.x = 2; //修改obj2.x
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 2, y: 2}

var obj1 = {
    x: 1, 
    y: {
        m: 1
    }
};
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 2}}
console.log(obj2) //{x: 2, y: {m: 2}}

Array

slice(), concat, Array.from(), spread operator (...), concat, for loop

var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice();
console.log(arr1); //[1, 2, [3, 4]]
console.log(arr2); //[1, 2, [3, 4]]

arr2[0] = 2 
arr2[2][1] = 5; 
console.log(arr1); //[1, 2, [3, 5]]
console.log(arr2); //[2, 2, [3, 5]]

How to implement deep copy

JSON.parse(JSON.stringify(obj))

During the serialization process of JSON.stringify(), undefined, arbitrary functions and symbol values ​​will be ignored during the serialization process (appearing in non- when it is in the property value of an array object) or is converted to null (when it appears in an array).

var obj1 = {
    x: 1, 
    y: {
        m: 1
    },
    a:undefined,
    b:function(a,b){
      return a+b
    },
    c:Symbol("foo")
};
var obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ƒ, c: Symbol(foo)}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ƒ, c: Symbol(foo)}
console.log(obj2) //{x: 2, y: {m: 2}}

Simple implementation of deep copy function

function deepClone(obj){
  let result = Array.isArray(obj)?[]:{};
  if(obj && typeof obj === "object"){
    for(let key in obj){
      if(obj.hasOwnProperty(key)){
        if(obj[key] && typeof obj[key] === "object"){
          result[key] = deepClone(obj[key]);
        }else{
          result[key] = obj[key];
        }
      }
    }
  }
  return result;
}

var obj1 = {
    x: {
        m: 1
    },
    y: undefined,
    z: function add(z1, z2) {
        return z1 + z2
    },
    a: Symbol("foo"),
    b: [1,2,3,4,5],
    c: null
};
var obj2 = deepClone(obj1);
obj2.x.m = 2;
obj2.b[0] = 2;
console.log(obj1);
console.log(obj2);

//obj1
{
a: Symbol(foo)
b: (5) [1, 2, 3, 4, 5]
c: null
x: {m: 1}
y: undefined
z: ƒ add(z1, z2)
}

//obj2
{
a: Symbol(foo)
b: (5) [2, 2, 3, 4, 5]
c: null
x: {m: 2}
y: undefined
z: ƒ add(z1, z2)
}

The above deep copy method encounters a circular reference and will fall into a cyclic recursive process, causing the stack to explode. Therefore improvements are needed.

Improvement of deep copy function (preventing loop recursion)

To solve the problem of stack explosion due to loop recursion, you only need to determine whether the fields of an object refer to this object or any parent of this object Level is enough.

function deepClone(obj, parent = null){ // 改进(1)
  let result = Array.isArray(obj)?[]:{};
  let _parent = parent;  // 改进(2)
  while(_parent){ // 改进(3)
    if(_parent.originalParent === obj){
      return _parent.currentParent;
    }
    _parent = _parent.parent;
  }
  if(obj && typeof obj === "object"){
    for(let key in obj){
      if(obj.hasOwnProperty(key)){
        if(obj[key] && typeof obj[key] === "object"){
          result[key] = deepClone(obj[key],{ // 改进(4)
            originalParent: obj,
            currentParent: result,
            parent: parent
          });
        }else{
          result[key] = obj[key];
        }
      }
    }
  }
  return result;
}

// 调试用
var obj1 = {
    x: 1, 
    y: 2
};
obj1.z = obj1;
var obj2 = deepClone(obj1);
console.log(obj1); 
console.log(obj2);

Final version of deep copy function (supports basic data types, prototype chains, RegExp, and Date types)

function deepClone(obj, parent = null){ 
  let result; // 最后的返回结果

  let _parent = parent; // 防止循环引用
  while(_parent){
    if(_parent.originalParent === obj){
      return _parent.currentParent;
    }
    _parent = _parent.parent;
  }
  
  if(obj && typeof obj === "object"){ // 返回引用数据类型(null已被判断条件排除))
    if(obj instanceof RegExp){ // RegExp类型
      result = new RegExp(obj.source, obj.flags)
    }else if(obj instanceof Date){ // Date类型
      result = new Date(obj.getTime());
    }else{
      if(obj instanceof Array){ // Array类型
        result = []
      }else{ // Object类型,继承原型链
        let proto = Object.getPrototypeOf(obj);
        result = Object.create(proto);
      }
      for(let key in obj){ // Array类型 与 Object类型 的深拷贝
        if(obj.hasOwnProperty(key)){
          if(obj[key] && typeof obj[key] === "object"){
            result[key] = deepClone(obj[key],{ 
              originalParent: obj,
              currentParent: result,
              parent: parent
            });
          }else{
            result[key] = obj[key];
          }
        }
      }
    }
  }else{ // 返回基本数据类型与Function类型,因为Function不需要深拷贝
    return obj
  }
  return result;
}

// 调试用
function construct(){
    this.a = 1,
    this.b = {
        x:2,
        y:3,
        z:[4,5,[6]]
    },
    this.c = [7,8,[9,10]],
    this.d = new Date(),
    this.e = /abc/ig,
    this.f = function(a,b){
        return a+b
    },
    this.g = null,
    this.h = undefined,
    this.i = "hello",
    this.j = Symbol("foo")
}
construct.prototype.str = "I'm prototype"
var obj1 = new construct()
obj1.k = obj1
obj2 = deepClone(obj1)
obj2.b.x = 999
obj2.c[0] = 666
console.log(obj1)
console.log(obj2)
console.log(obj1.str)
console.log(obj2.str)

Note: Deep copy of Function type:

bind(): Use fn.bind() to make a deep copy of the function, but it cannot be used because of the problem with the this pointer;

eval(fn.toString()): Only arrow functions are supported. Ordinary function function fn(){} is not applicable;

new Function(arg1,arg2,...,function_body): The parameters and function body need to be extracted;

PS: Generally not A deep copy of Function is required.

[Related recommendations: javascript learning tutorial]

The above is the detailed content of Detailed explanation of JavaScript basic objects (organized and shared). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete