JS 对象

对象

JS 中,对象的 key 都会被转为 string 类型。

  如:

const obj = { 1: 'a', 2: 'b', 3: 'c' };
obj.hasOwnProperty('1');  // true
obj.hasOwnProperty(1);  // true

  再如,以一个对象为 key,同样会被转为 string

const a = {};
const b = { key: 'b' };
const c = { };

a[b] = 123;
a[c] = 456;

console.log(a[b]); // 456

  对象 aimage-20200416203843666

  上面的代码中, 对象 b 和对象c 都被当做一个 key,而对象的 key 会被转为字符串,因此 bc 会被转为:"[object Object]",所以,代码中表示 a["object Object"] = 123,所以最后变成了 456

  当我们调用 a[b] 的时候,相当于调用了 a["object Object"]

  不过若是用 a.b 的话,b 就是代表一个字符 b

判断对象是否为空

1. object.keys()

var data = {};
var arr = Object.keys(data);
alert(arr.length == 0); //true 为空, false 不为空

2.将对象转化为json字符串,再判断该字符串是否为"{}"

var data = {};
var b = (JSON.stringify(data) == "{}");
alert(b);   //true 为空, false 不为空

3.for in 循环判断

var obj = {};
var b = function() {
    for(var key in obj) {
        return false;
    }
    return true;
}

4.Object.getOwnPropertyNames()方法

  此方法是使用 Object 对象的 getOwnPropertyNames 方法,获取到对象中的属性名,存到一个数组中,返回数组对象,我们可以通过判断数组的 length 来判断此对象是否为空。

var data = {};
var arr = Object.getOwnPropertyNames(data);
alert(arr.length == 0);//true

比较对象中的内容是否相同,编写 Object.equals 函数

  注意,在 equals 中没有使用 === 进行比较,因为 === 会比较对象的引用是否相同,而我们只想比较内容是否相同:

Object.prototype.equals = function(obj) {
    // For first loop , we only check for types
    for (let propName in this) {
        // Check for inherited methods and properties
        if (this.hasOwnProperty(propName) != obj.hasOwnProperty(propName)) {
            return false;
        }

        // Check instance type
        if (typeof this[propName] != typeof obj[propName]) {
            return false;
        }
    }

    // A deeper check using other objects property names
    for (let propName in obj) {
        // We must check instances anyway, there may be a property exits in obj
        if (this.hasOwnProperty(propName) != obj.hasOwnProperty(propName)) {
            return false;
        }

        if (typeof this[propName] != typeof obj[propName]) {
            return false;
        }

        // If the property is inherited, do not check any more (it must be equal if both objects inherit it)
        if (!this.hasOwnProperty(propName)) {
            continue;
        }

        // Now the detail check and recursion

        // Requires Array.equals !!!
        if (this[propName] instanceof Array && obj[propName] instanceof Array) {
            // recurse into the nested arrays
            if (!this[propName].equals(obj[propName])) {
                return false;
            }
        } else if (this[propName] instanceof Object && obj[propName] instanceof Object) {
            // recurse into other objects
            // console.log("Recursing to compare ", this[propName],"with",obj[propName], " both named \""+propName+"\"");
            if (!this[propName].equals(obj[propName])) {
                return false;
            }
        } else if (this[propName] != obj[propName]) {  // Normal value comparsion for strings and numbers
            return false;
        }
    }
    return true;
}

  一个 Array,prototype.equals 的实现

  上面代码中还需要实现 Array.prototype.equals 方法,这边模拟时就先都返回 true

Array.prototype.equals = function(arr) {
    return true;
};

let obj1 = {
    name: 'yy',
    age: '15',
    objs: {
        obj1: '教师',
        obj2s: ['程序员', '码农'],
        obj3s: {
            obj3_1: '互联网员工',
            obj3_2: '社畜'
        }
    }
};

let obj2 = {
    name: 'yy',
    age: '15',
    objs: {
        obj1: '教师',
        obj2s: ['程序员', '码农'],
        obj3s: {
            obj3_1: '互联网员工',
            obj3_2: '社畜'
        }
    }
};

console.log(obj1.equals(obj2)); // true

对象的一些方法

Object.prototype.hasOwnProperty()

MDN 文档

  hasOwnProperty 方法可以检测某个属性是否是该对象自身的(不包括原型链上的属性),若是,返回 true ,否则返回 false

例:

function Obj() {
    this.name = 'obj';
}

Obj.prototype = {
    age: 12
};

Object.prototype.job = 'new Job';

let o = new Obj();

for (let v in o) {
    console.log(v, o.hasOwnProperty(v));
}

  程序输出:

name true
age false
job false

Object.defineProperty()

  Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象

  语法:Object.defineProperty(obj, prop, descriptor)

  • obj : 要在其上定义属性的对象。
  • prop : 要定义或修改的属性的名称。
  • descriptor : 将被定义或修改的属性描述符。

例:

const person = { name: "Lydia" };

Object.defineProperty(person, "age", { value: 21 });

console.log(person); // { name: "Lydia", age: 21 }
console.log(Object.keys(person)); // ["name"]

  可修改 descriptor 来设置添加的属性。

  • configurable : 默认为 false,当设置为 true 时,descriptor 才可被修改,同时该属性也能从对应的对象上被删除。
  • enumerabel : 默认为 false,设置为 true 时,新添加的属性才能被枚举
  • value : 默认为 undefined,可以是任何有效的 JS 值(数值,对象,函数等)
  • writable : 默认为 false,设置为 true 时,value 才能被赋值运算符修改。
  • get : 默认为 undefined,一个给属性提供 getter 的方法,当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入 this 对象
  • set : 默认为 undefined,一个给属性提供 setter 的方法,当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。

Object.entries

  Object.entries(obj) 方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致,即属性的顺序与通过手动循环对象的属性值所给出的顺序相同。(区别在于 for-in 循环还会枚举原型链中的属性)。

例:

const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]

// 字符串
console.log(Object.entries('foo')); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ]

  使用 for ... of 和解构赋值遍历:

// 使用 for - of 和 解构赋值 遍历结果
const obj = { a: 5, b: 7, c: 9 };
for (const [key, value] of Object.entries(obj)) {
    console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
}

  使用 forEach 遍历:

Object.entries(obj).forEach(([key, value]) => {
    console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});

  new Map() 构造函数接受一个可迭代的 entries。借助 Object.entries 方法你可以很容易的将 Object 转换为 Map:

var obj = { foo: "bar", baz: 42 }; 
var map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }

Object.assign()

MDN介绍

  Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象

  如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。

  语法:Object.assign(target, ...sources)

  • target: 目标对象。
  • sources: 源对象。

返回值:目标对象。

  注意Object.assign 不会在那些source对象值为 nullundefined 的时候抛出错误。

例:

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target); // Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget); //Object { a: 1, b: 4, c: 5 }

  复制一个对象:

const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

  针对深拷贝,需要使用其他办法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用

let obj1 = { a: 0 , b: { c: 0}}; 
let obj2 = Object.assign({}, obj1); 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 

obj1.a = 1; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 

obj2.a = 2; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
 
// 改变源对象中的对象属性值,拷贝对象会跟着改变,因为只是拷贝了对象的引用
obj2.b.c = 3; 
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} 
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} 

  深克隆:

// Deep Clone 
obj1 = { a: 0 , b: { c: 0}}; 
let obj3 = JSON.parse(JSON.stringify(obj1)); 
obj1.a = 4; 
obj1.b.c = 4; 
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

 目录