# is

  • 此API为ES6新增API
  • Object.is() 方法判断两个值是否是相同的值
  • 在ES6之前判断两个值是否相等只有=====,现在我们多了个选择可以使用Object.is()
  • 语法:Object.is(value1, value2);
    • value1 第一个需要比较的值
    • value2 第二个需要比较的值
    • 返回值 表示比较结果的布尔值
const obj1 = {name: '张三'};
console.log(Object.is(obj1, {name: '张三'})); // false
console.log(obj1 === {name: '张三'}); // false
console.log(obj1 == {name: '张三'}); // false

console.log(Object.is(obj1, obj1)); // true
console.log(obj1 === obj1); // true
console.log(obj1 == obj1); // true

const num1 = +0;
console.log(Object.is(num1, -0)); // false
console.log(num1 === -0); // true
console.log(num1 == -0); // true
1
2
3
4
5
6
7
8
9
10
11
12
13

补充:js对于引用类型的比较实质是内存地址的比较,而不是内容的比较;对于原始类型的比较是值得比较

其实Object.is() 基本和=== 是一样的,不同的地方就是:一是+0不等于-0(在===+0 === -0是true),二是NaN等于自身(在===NaN === NaN是false)

== 的比较会先进行类型转换再进行比较,而=== 不会。这两区别在最开始学习js的时候应该是有进行了解的

# assign

  • 此API是ES6新增的API
  • assign() 用于将一个或多个对象的可枚举属性拷贝到目标对象,并返回目标对象
  • assign() 简单讲就是多个对象合并,但如果目标对象(要合入的对象)和来源对象(拷贝来源对象的属性粘贴到目标对象)有相同的key,则来源对象的key会覆盖目标对象的key,来源对象后面还有若干个来源对象,则后面的会覆盖前面的。
  • 该操作会修改目标对象
  • Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用
  • 语法:Object.assign(target, ...sources)
    • target 目标对象
    • sources 源对象
    • 返回值 目标对象
const target = {name: '李白', id: 1098};
const sources1 = {sexCode: 1, age: 99, id: 1010};
const sources2 = {name: '杜甫', id: 1209, height: 170};

const result = Object.assign(target,sources1,sources2);
console.log(result); // { name: "杜甫", id: 1209, sexCode: 1, age: 99, height: 170 } 源对象与目标对象相同的key 后者会覆盖前者
console.log(target); // { name: "杜甫", id: 1209, sexCode: 1, age: 99, height: 170 } assign 会修改目标对象
console.log(sources1); // { sexCode: 1, age: 99, id: 1010 }
console.log(sources2); // { name: "杜甫", id: 1209, height: 170 }
1
2
3
4
5
6
7
8
9
const sources1 = {sexCode: 1, age: 99, id: 1010};
const sources2 = {name: '杜甫', id: 1209, height: 170};
const sources3 = {sources: sources2};
const result2 = Object.assign(sources1,sources2,sources3);
console.log(result2);
// 输出 { sexCode: 1, age: 99, id: 1209, name: "杜甫", height: 170, sources: Object { name: "杜甫", id: 1209, height: 170 } }
sources2.weight = '68kg';
console.log(result2);
// 输出 { sexCode: 1, age: 99, id: 1209, name: "杜甫", height: 170, sources: Object { name: "杜甫", id: 1209, height: 170, weight: "68kg" } }
console.log(sources2);
// 输出 { name: "杜甫", id: 1209, height: 170, weight: "68kg" }
console.log(sources3);
// 输出 { sources: Object { name: "杜甫", id: 1209, height: 170, weight: "68kg" } }
1
2
3
4
5
6
7
8
9
10
11
12
13

sources3 对象的sources 属性是引用的sources2 对象,所以sources2 对象被修改,sources3sources 的值就会同步被修改。

sources1 对象将sources3 对象的sources 属性拷贝进去了,sources3 对象的sources 引用的是sources2 对象,所以 ,最终也就是sources1对象sources 也引用了sources2 对象,所以sources2 修改的同时,所有引用了它的(对象),都会被修改

const sources = {sexCode: 1, id: 1010};
Object.defineProperty(sources, 'age', {
  enumerable: false,
  value: 99,
});
console.log(sources); // 输出 {sexCode: 1, id: 1010, age: 99}
const result = Object.assign({},sources);
console.log(result); // 输出 {sexCode: 1, id: 1010}
1
2
3
4
5
6
7
8

sources 是源对象,我们给其设置了一个age 的不可枚举属性,使用assign() API 将其合并入一个空数组,由于age 属性是不可枚举的,所以age 并没有被assign()进行拷贝

此API在IE浏览器不支持,如果需要兼容IE浏览器,可以在js顶部添加如下代码;(如下代码来自MDN

if (typeof Object.assign != 'function') {
  // Must be writable: true, enumerable: false, configurable: true
  Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) { // .length of function is 2
      'use strict';
      if (target == null) { // TypeError if undefined or null
        throw new TypeError('Cannot convert undefined or null to object');
      }

      let to = Object(target);

      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];

        if (nextSource != null) { // Skip over if undefined or null
          for (let nextKey in nextSource) {
            // Avoid bugs when hasOwnProperty is shadowed
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# keys

  • Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 [`for...in` 循环遍历该对象时返回的顺序一致 。
  • 给定对象 并非表示必须是Object类型,Array也可以使用此方法
  • 如果给定对象是Object,返回的就是这个对象所有可枚举属性的key(键)所组成的数组;如果给定对象是一个Array,返回的就是这个数组元素索引(索引会被转成字符串)所组成的数组
  • 语法:Object.keys(obj)
    • obj 要返回其枚举自身属性的对象。
    • 返回值 一个表示给定对象的所有可枚举属性的字符串数组
const obj = {name: '李白', sexCode: 1, height: 170};
const arr = ['李白', ['height',170], ['sexCode', 1]];
const str = 'hello world';

const objKeys = Object.keys(obj); // 输出 ["name", "sexCode", "height"]
const arrKeys = Object.keys(arr); // 输出 ["0", "1", "2"]
const strKeys = Object.keys(str); // 输出 ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

// 拿到key值组成的数组后,就可以换种方式去遍历对象(虽然for...of...非常香)
objKeys.forEach(key => {
  console.log(obj[key])
});
1
2
3
4
5
6
7
8
9
10
11
12

# values

  • 此API是ES8新加的,IE不支持
  • Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )
  • Object.values()Object.keys() 是相对的,keys() 返回键组成的数组,value() 返回值组成的数组
  • 语法:Object.values(obj)
    • obj 被返回可枚举属性值的对象。
    • 返回值 一个包含对象自身的所有可枚举属性值的数组。
const obj = {name: '李白', sexCode: 1, height: 170};
const arr = ['李白', ['height',170], ['sexCode', 1]];
const str = 'hello world';

const objValues = Object.values(obj); // 输出 ["李白", 1, 170]
const arrValues = Object.values(arr); // 输出 ["李白", ["height", 170], ["sexCode", 1]]
const strValues = Object.values(str); // 输出 ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]

// 结合数组的 every() 和 some() 来做数据校验
const res = objValues.some(item => item === '李白');
1
2
3
4
5
6
7
8
9
10

如过希望在低版本浏览器和IE,可以在代码起始位置写下如下内容:(如下代码来自MDN

if (!Object.values) Object.values = function(obj) {
    if (obj !== Object(obj))
        throw new TypeError('Object.values called on a non-object');
    var val=[],key;
    for (key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj,key)) {
            val.push(obj[key]);
        }
    }
    return val;
}
1
2
3
4
5
6
7
8
9
10
11

# entries

  • 此API是ES8新加的,IE不支持
  • Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)
  • Object.entries()Object.values()Object.keys() 可以算是一套的API,Object.values()Object.keys() 前文已经说了,Object.entries() 就是将这两个合起来,返回的[[key1,value1],[key2,value2]] 格式
  • 适用: 将一个Object 转换成Map
  • 语法:Object.entries(obj)
    • obj 可以返回其可枚举属性的键值对的对象。
    • 返回值 给定对象自身可枚举属性的键值对数组。
const obj = {name: '李白', sexCode: 1, height: 170};
const arr = ['李白', ['height',170], ['sexCode', 1]];
const str = 'hello world';

const objEntries = Object.entries(obj); // 输出 [["name", "李白"], ["sexCode", 1], ["height", 170]]
const arrEntries = Object.entries(arr);
// 格式 [[索引, 元素]]
// 输出 [["0", "李白"], ["1", ["height", 170]], ["2", ["sexCode", 1]]]
const strEntries = Object.entries(str);
// 格式 [[索引, 值]]
// 输出 [["0", "h"], ["1", "e"], ["2", "l"], ["3", "l"], ["4", "o"], ["5", " "], ["6", "w"], ["7", "o"], ["8", "r"], ["9", "l"], ["10", "d"]]

// 转成Map对象
const objMap = new Map(objEntries);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

兼容低版本和IE,代码起始位置写下如下内容:(如下代码来自MDN Polyfill

if (!Object.entries)
  Object.entries = function( obj ){
    var ownProps = Object.keys( obj ),
        i = ownProps.length,
        resArray = new Array(i); // preallocate the Array
    while (i--)
      resArray[i] = [ownProps[i], obj[ownProps[i]]];
    
    return resArray;
  };
1
2
3
4
5
6
7
8
9
10

# fromEntries

  • 此API在ES10草案中被提出,目前尚未写入JS标准
  • Object.fromEntries() 方法把键值对列表转换为一个对象
  • Object.fromEntries()Object.entries(obj) 是相反的,Object.entries(obj) 将对象转换成键值对列表,Object.fromEntries() 则将键值对列表还原成对象
  • 适用:Map 转换成Object
  • 语法:Object.fromEntries(iterable)
    • iterable 可迭代对象,类似 ArrayMap 或者其它实现了可迭代协议的对象。
    • 返回值 一个由该迭代对象条目提供对应属性的新对象(返回一个Object)。
const objEntries = [["name", "李白"], ["sexCode", 1], ["height", 170]];
const objMap = new Map(objEntries);

const obj1 = Object.fromEntries(objEntries); // 输出 { name: "李白", sexCode: 1, height: 170 }
const obj2 = Object.fromEntries(objMap); // 输出 { name: "李白", sexCode: 1, height: 170 }
1
2
3
4
5

此API未写入js标准,IE及Edge浏览器不支持,Chrom、Firefox、Opera以及Safari稍微低一点的版本也都不支持,不建议在生产环境使用此API

# 属性简洁表示法

  • 实用度:
  • 常用度:
  • 属性的简洁表示在ES6中引入,它允许我们以更加简洁的方式来写属性,2019年应该没有人没用过了吧
const name = '李白';
const sexCode = 1;
const obj = {
  name, // 等于 name: name,
  sexCode, // 等于 sexCode: sexCode
  // 函数等于 getHeight: function() {}
  getHeight() {
    return 170;
  }
}
1
2
3
4
5
6
7
8
9
10

# 属性名表达式

想象一下这个场景:在商城系统中一个订单从生成到完成,这个订单会有一系列的状态,在数据库中这个订单存的是代表状态的code码,接口给我们返回的也是code码,前端如何来处理将code码转换成汉字状态。

// 我们可以先定义一个对象,将所有的状态列出来
const state = {
  'A': '未付款',
  'B': '待发货',
  'C': '已发货',
  'D': '已完成',
  'E': '已评价',
}

// 我们正常取对象的属性是这么取的
console.log(state.A); // 输出 未付款

// 但现在这个状态是后端给我们返回的,也就是无法确定,所以我们更希望可以用变量来取对象的属性
const key = 'A';
console.log(state[key]); // 使用变量来表示键名 我们可以随意给key赋值 输出未付款
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

完成示例

// 其实我们定义的时候也可以在方括号内写变量和表达式
const key = 'state';
const state = {
  [key]: '状态',
  ['A' + 'B']: '未付款但已发货',
  [`${key}A`]: '状态未付款'
}
console.log(state); // 输出 { state: "状态", AB: "未付款但已发货", stateA: "状态未付款" }
1
2
3
4
5
6
7
8

# 其他(不常用)

# freeze

  • Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
  • Object.freeze() 相当于将一个对象变为只读状态;但是如果这个对象的某个属性的值还是一个对象(A),则这个A可读可写,除非这个A也是冻结状态;数组作为一种对象,被冻结,其元素也不能被修改,即这个数组元素不能被删除,也不能在添加
  • 语法:Object.freeze(obj)
    • obj 要被冻结的对象。
    • 返回值 被冻结的对象
const people = {
  name: '李白'
}
Object.freeze(people);
people.age = 102;
console.log(people); // 输出 {name: "李白"}  age属性并没有写进去
1
2
3
4
5
6

# isFrozen

  • Object.isFrozen()方法判断一个对象是否被冻结。
  • 语法:Object.isFrozen(obj)
    • obj 被检测的对象
    • 返回值 Boolean 检测结果
const people = {
  name: '李白'
}
let res = Object.isFrozen(people); // false 未冻结
console.log(res)

Object.freeze(people);
res = Object.isFrozen(people);
console.log(res); // true 已冻结
1
2
3
4
5
6
7
8
9

# seal

  • Object.seal() 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。

  • Object.seal()Object.freeze() 的区别是,Object.seal() 封闭之后,对象的属性可以修改,但不能添加和删除新属性;Object.freeze() 冻结之后不可添加不可删除不可修改

  • 语法:Object.seal(obj)

    • obj 将要被密封的对象。
    • 返回值 被密封的对象。
const people = {
  name: '李白'
}
Object.seal(people);
people.age = 102;
people.name = '杜甫';
console.log(people); // 输出 {name: "杜甫"}  age属性并没有写进去 但 name被修改了
1
2
3
4
5
6
7

# isSealed

  • Object.isSealed() 方法判断一个对象是否被密封。
  • 语法:Object.isSealed(obj)
    • obj 要被检查的对象。
    • 返回值 Boolean 检测结果
const people = {
  name: '李白'
}
let res = Object.isSealed(people); // false 未密封
console.log(res)

Object.seal(people);
res = Object.isSealed(people);
console.log(res); // true 已密封
1
2
3
4
5
6
7
8
9
Last Updated: 4/27/2020, 10:56:04 PM