Skip to content
On this page

对象

记录对象中的 api

属性

分为 常规属性(properties ) 和 排序属性(elements)

常规属性是键为字符串的属性(除了数字字符串)特点是根据创建时的顺序排序
排序属性是键为数字的属性,特点是根据数字排序
两个属性都有时,排序属性先于常规属性

快属性与慢属性

elements 对象和 properties 对象都是用线性结构存储属性的,但这样存在效率问题,因为在查某个属性的时候,要先去查 elements 对象或 properties 对象,增加了查找步骤。

为了减轻这个问题,引擎会将部分常规属性(默认是 10 个)直接存到对象下面,称为对象内属性

1、将保存在线性结构里的属性称为快属性,快属性查找快,增删慢;

2、当对象属性很多的时候,就会放大线性结构增删属性的缺点,因此引擎会利用非线性结构(字典)来保存属性,这时候被存储的属性称为慢属性

解构

解构是一层 浅拷贝

⭐undefined / null

每个解构属性都可以有一个默认值。当属性 不存在或值为 undefined 时,将使用默认值。

如果属性的值为 null,无法使用默认值。

js
const [ a = 1 ] = []; // a is 1
const { b = 2 } = { b: undefined }; // b is 2
const { c = 2 } = { c: null }; // c is null

赋值给新的变量名

js
const o = { p: 42, q: true };
const { p: foo, q: bar } = o;

console.log(foo); // 42
console.log(bar); // true

原理是

js
var o = { p: 42, q: true };
var foo = o.p, bar = o.q;

这么长时间过去了,还是记不住2024/2/1

赋值到新的变量名并提供默认值

一个属性可以同时是两者:

  • 从对象提取并分配给具有不同名称的变量。
  • 指定一个默认值,以防获取的值为 undefined。
js
const { a: aa = 10, b: bb = 5 } = { a: 3 };

console.log(aa); // 3
console.log(bb); // 5

从作为函数参数传递的对象中提取属性

js
const user = {
  id: 42,
  displayName: 'jdoe',
  fullName: {
    firstName: 'Jane',
    lastName: 'Doe',
  },
};

解构 id 属性

js
function userId({ id }) {
  return id;
}
console.log(userId(user)); // 42

重新命名

js
function userDisplayName({ displayName: dname }) {
  return dname;
}

console.log(userDisplayName(user)); // `jdoe`

相当于

js
function userDisplayName(_a) {
    var dname = _a.displayName;
    return dname;
}

嵌套对象

js
function whois({ displayName, fullName: { firstName: name } }) {
  return `${displayName} is ${name}`;
}

console.log(whois(user));  // "jdoe is Jane"

可以把解构看成 {k:v} 形式,然后与传入对象一一对应, 所以 v 就是最终形式

设置函数参数的默认值

一定要写 {} , 因为如果 drawChart 不传值的时候, 无法解构

js
function drawChart(
  { size = 'big', coords = { x: 0, y: 0 }, radius = 25 } = {}) {
  console.log(size, coords, radius);
}

drawChart({
  coords: { x: 18, y: 30 },
  radius: 30,
});

组合数组和对象解构

js
const props = [
  { id: 1, name: 'Fizz'},
  { id: 2, name: 'Buzz'},
  { id: 3, name: 'FizzBuzz'}
];

const [,, { name }] = props;

console.log(name); // "FizzBuzz"

解构对象时查找原型链

当解构一个对象时,如果属性本身没有被访问,它将沿着原型链继续查找。

js
const obj = {
  self: '123',
  __proto__: {
    prot: '456',
  },
};
const { self, prot } = obj;
// self "123"
// prot "456" (Access to the prototype chain)

Object.create

Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype)

js
const person = {
  isHuman: false,
  printIntroduction: function() {
    console.log(this)
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  }
};

const me = Object.create(person);

console.log(me.__proto__ == person) // true

Object.is

  • 严格相等比较 (也被称作"strict equality", "identity", "triple equals"),使用 === ,
  • 抽象相等比较 ("loose equality","double equals") ,使用 ==
  • Object.is (ECMAScript 2015/ ES6 新特性)

TIP

⭐ Object.is() 与 === 也不相同。差别是它们对待有符号的零和 NaN 不同,例如,=== 运算符(也包括 == 运算符) 将数字 -0 和 +0 视为相等,而将 NaN 与 NaN 视为不相等

js
Object.is(0, -0);            // false 
Object.is(0, +0);            // true
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true
js
+0 === -0 // true

NaN === NaN // false

Object.fromEntries / Object.entries

from 从语义理解, 即一个键值对列表创建一个对象。

entries 是小条目,即 [k : v] 形式

Object.fromEntries(iterable) 列表转换为一个对象。
Object.entries(Object) 将对象转化为列表。

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

const queryString = "?name=jimmy&age=18&height=1.88";
const queryParams = new URLSearchParams(queryString);

// URLSearchParams { 'name' => 'jimmy', 'age' => '18', 'height' => '1.88' }
queryParams // 和 Map 的数据结构一致

const paramObj = Object.fromEntries(queryParams);
console.log(paramObj); // { name: 'jimmy', age: '18', height: '1.88' }

处理 Array

js
const arr = [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ];
const obj = Object.fromEntries(arr);
console.log(obj); // { 0: "a", 1: "b", 2: "c" }

Object.assign

Object.assign() 静态方法将一个或者多个源对象中所有可枚举的自有属性复制到目标对象,并返回修改后的目标对象。

TIP

Object.assign() 不会在 source 对象值为 null 或 undefined 时抛出错误

原型链上的属性和不可枚举属性不能被复制

js
const v1 = 'abc';
const v2 = true;
const v3 = 10;
const v4 = Symbol('foo');

const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始类型会被包装,null 和 undefined 会被忽略
// 注意,只有字符串封装对象才拥有可枚举的自有属性。 
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

{...undefined} // {}
{...true} // {}
// 类似于 Object.assign({},undefined)

TIP

个人理解: Object.assigniterator 属性的转化为对象形式,所以 abc 可以被转成 { 0:'a', 1:"b", 2:'c' }

展开语法

将数组表达式或者 string 在语法层面展开;还可以在构造字面量对象时,将对象表达式按 key-value 的方式展开 对于不能展开的语法,直接返回 {}

js
{...undefined}  // {}
{...null}  // {}
{...1} // {}
{...false} // {}
{...'abcd'} // { 0:'a', 1:'b', 2:'c', 3:'d' }

INFO

展开语法也是对 可迭代对象 有效

null / undefined

js
var obj = {}
 obj.a // undefined
 document.getElementById('a') // null
 document.parentNode // null

⭐ null 表示无对象,也可以表示为一个对象,但他什么也没有,比如这个 document 本身应该有对象,但没有所以是 null, 也可以理解为 在 栈内存中没有引用堆内存中的指针

undefined 表示没 value 值,也可以表示为有 value 值,这个 value 就是 undefined-暂不确定的值
js
Number(null) // 0
// 把他当做 值使用
Number(undefined) // NaN 


null == 0 // false
undefined == 0 // false
// 从语义上理解, null 和 undefined 都是表示无值,只不过一个没有对象,一个是没有值
null == undefined // true

🔗可迭代对象

js
let o = {
  a:1,
  b:2
}
let [a,b] = o;

因为 o 不是一个可迭代对象,所以会报错,需要把 o 变为可迭代对象,添加 Symbol.iterator 方法并返回 next 对象

js
let o = {
  a: 1,
  b: 2,
  [Symbol.iterator]() {
    let values = Object.values(this);
    let index = 0;
    return {
      next: () => {
        if (index <= values.length) {
          let value = values[index];
          index++;
          return { value, done: false };
        } else {
          return {
            done: true
          }
        }
      }
    }
  }
}

设置/获取 可枚举

js
Object.defineProperty(obj, "key2", {
  enumerable: false,   
  configurable: false,
  writable: false,
  value: "static",
});

🔗获取属性

js
const obj = {
  name: 'John',
  age: 25
};

const descriptor = Object.getOwnPropertyDescriptor(obj, 'name');
// { 
//   value: 'John',
//   writable: true,
//   enumerable: true,
//   configurable: true
// }
console.log(descriptor);