Object 对象

重要通知

类目简介

基本概况

创建对象

  • Object.create、new Object

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__ 返回一个新对象,带着指定的原型对象和属性。 如果propertiesObject参数是 null 或非原始包装对象,则抛出一个 TypeError 异常。

const obj = Object.create(
  proto,               // 新创建对象的原型对象
  [propertiesObject]   // 可选。需要传入一个对象,该对象的属性类型参照Object.defineProperties()的第二个参数。
);

let man1 = Object.create(null);
let man2 = new Object(null);
let man3 = null;

console.log(man1);  // {}  No properties
console.log(man2);  // {}  [[Prototype]]: Object
console.log(man3);  // null

let Students = { sex: '女', name: '大美女', count: 100, list: [] };
let women1 = Object.create(Students);
let women2 = new Object(Students);
let women3 = Students;

console.log(women1);
console.log(women2);
console.log(women3);

// 判断该对象是否具有Students对象的相关属性
console.log(women1.hasOwnProperty('name'));  // false
console.log(women2.hasOwnProperty('name'));  // true
console.log(women3.hasOwnProperty('name'));  // true

// 判断该对象是否在Students对象的原型链上
console.log(Students.isPrototypeOf(women1));  // true
console.log(Students.isPrototypeOf(women2));  // false
console.log(Students.isPrototypeOf(women3));  // false

创建空对象

该空对象没有继承 Object.prototype 原型链上的属性或者方法。

let student = Object.create(null);
console.log(student);   // {}  No properties

删除对象属性

const user = { name: "Charlie", id: 123 };
Reflect.deleteProperty(user, 'id');
console.log(user); // { name: "Charlie" }

JSON对象

JSON.stringify缺陷: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

console.info(JSON.parse());            // SyntaxError
console.info(JSON.parse(null));        // null
console.info(JSON.parse(undefined));   // SyntaxError
console.info(JSON.parse(0));           // 0
console.info(JSON.parse(true));        // true
console.info(JSON.parse(''));          // SyntaxError
console.info(JSON.parse([]));          // SyntaxError
console.info(JSON.parse({}));          // SyntaxError
console.info(JSON.parse(Symbol('')));  // SyntaxError

基本属性

基本方法

属性

Object.constructor:返回 Object 的构造函数

基础方法

Object.create():创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 [object].hasOwnProperty(key):判断对象是否包含指定属性。 [obejct].isPrototypeOf(object):判断对象的原型链上是否包含指定对象。 Object.setPrototypeOf():设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。[严重影响性能] Object.getPrototypeOf():返回指定对象的原型(内部[[Prototype]]属性的值)。 [object].propertyIsEnumerable(key):判断指定属性在对象中是否可枚举。 [object].toLocaleString([locales [, options]]):返回一个该对象的字符串表示。 [object].toString():返回一个表示该对象的字符串。 [object].valueOf():返回指定对象的原始值。

  function Students() {}
  const zhangsan = new Students();
  const students = {name: '李明', principal: '李大钊', address: '北京市', history: {}};
  students.sex = '男';
  const dog = {};
  const zoo = Object.create(dog);

  console.log(students.hasOwnProperty('name'));               // true
  console.log(Students.prototype.isPrototypeOf(zhangsan));    // true
  console.log(Object.setPrototypeOf({}, null));               // [Object: null prototype] {}
  console.log(Object.getPrototypeOf(zoo) === dog);            // true
  console.log(students.propertyIsEnumerable('name'));         // true
  console.log(students.toString());                           // [object Object]
  console.log(students.valueOf());                            // { name: '李明', principal: '李大钊', address: '北京市', history: {}, sex: '男' }

核心方法

  • bject.assign(target, ...sources):用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。

  • Object.defineProperties():直接在一个对象上定义新的属性或修改现有属性,并返回该对象。

  • Object.defineProperty():直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

  • Object.entries(object):返回一个给定对象自身可枚举属性的键值对数组

  • Object.keys(object):返回一个给定对象自身可枚举属性的键数组

返回对象 o 自身包含(不包括原型中)的所有可枚举属性的名称的数组。

  • Object.values(object):返回一个给定对象自身可枚举属性的值数组
  • Object.freeze(object):冻结对象的属性描述符
  • Object.isFrozen(object):
  • Object.seal(object):封闭对象的属性描述符(当前属性的值只要原来是writable可写的就可以改变)
  • Object.isSealed(object):判断一个对象是否被冻结。
  • Object.fromEntries(maps):把键值对列表转换为一个对象
  • Object.getOwnPropertyDescriptor(object, property):返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
  • Object.getOwnPropertyDescriptors(object):获取一个对象的所有自身属性的描述符
  • Object.getOwnPropertyNames():返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组
  • Object.getOwnPropertySymbols(object):返回一个给定对象自身的所有 Symbol 属性的数组。
  • Object.is(value1, value2):判断两个值是否为同一个值。
  • Object.isExtensible(object):判断一个对象是否是可扩展
  • Object.preventExtensions(object):让一个对象变的不可扩展,也就是永远不能再添加新的属性。
  const students = {name: '李明', principal: '李大钊', address: '北京市', history: {}};
  students[Symbol('a')] = '标志';
  const entries = new Map([
    ['sex', '男']
  ]);
  console.log(Object.fromEntries(entries));                        // { sex: '男' }
  console.log(Object.getOwnPropertySymbols(students));             // [ Symbol(a) ]
  console.log(Object.getOwnPropertyNames(students));               // [ 'name', 'principal', 'address', 'history' ] 
  console.log(Object.getOwnPropertyDescriptors(students));         // { name: { value: '李明', writable: true, enumerable: true, configurable: true }, ... }
  console.log(Object.getOwnPropertyDescriptor(students, 'name'));  // { value: '李明', writable: true, enumerable: true, configurable: true }  
  • Object.assign(target...):用于将源对象的所有可枚举属性复制到目标对象中

如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转为对象然后返回 因为 null 和 undefined 不能转化为对象,所以会报错 当参数不止一个时,null 和 undefined 不放第一个,即不为目标对象时,会跳过 null 和 undefined ,不报错

  • Object.is(value1, value2):用来比较两个值是否严格相等,与(===)基本类似 console.log(Object.is(1, '1')); //false
// 合并对象,后者覆盖前者键值
let Students = {name: '李明', principal: '李大钊', address: '北京市', history: {}};
console.log({...Students, name: ''});               // { name: '', principal: '李大钊', address: '北京市', history: {} }
console.log(Object.assign(Students, { name: 2 }));  // { name: 2, principal: '李大钊', address: '北京市', history: {} }


Object.is('foo', 'foo');     // true
Object.is(window, window);   // true

Object.is('foo', 'bar');     // false
Object.is([], []);           // false

var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo);         // true
Object.is(foo, bar);         // false

Object.is(null, null);       // true

// 特例
Object.is(0, -0);            // false
Object.is(0, +0);            // true
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true  
  • Object.hasOwn()

旨在取代 Object.prototype.hasOwnProperty()。

const example = {};
Object.hasOwn(example, "prop"); // false——目标对象的属性 'prop' 未被定义

example.prop = "exists";
Object.hasOwn(example, "prop"); // true——目标对象的属性 'prop' 已被定义

example.prop = null;
Object.hasOwn(example, "prop"); // true——目标对象本身的属性存在,值为 null

example.prop = undefined;
Object.hasOwn(example, "prop"); // true——目标对象本身的属性存在,值为 undefined
  • hasOwnProperty():指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)
const SCHOOL = { students: 67332 };
SCHOOL.position = '北京市海淀区西三环';

console.log(SCHOOL.hasOwnProperty('students'));  // true
console.log(SCHOOL.hasOwnProperty('position'));  // true


// 防止迭代的时候进入到对象的原型属性中
for (var name in object) {  
    if (object.hasOwnProperty(name)) { 
        // do something with name
    }  
}
  • in:如果指定的属性在指定的对象或其原型链中,则in 运算符返回true。
const car = { make: 'Honda', model: 'Accord', year: 1998 };
console.log('make' in car);  // true
  • instanceof:检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car);  // true
  • Object.entries | Object.keys | Object.values
  let Person = { name: '张三', sex: '男', run() { console.log('赶紧跑'); } };

  // 遍历取得键与值的数组
  console.log(Object.entries(Person));  // [ [ 'name', '张三' ], [ 'sex', '男' ], [ 'run', [Function: run] ] ]
  for (let [key, value] of Object.entries(Person)) {
    console.log(`${key}: ${value}`);
  }

  // 遍历取得键的数组
  console.log(Object.keys(Person));     // [ 'name', 'sex', 'run' ]
  for (let i of Object.keys(Person)) {
    console.log(`${i}`);
  }

  // 遍历取得值得数组
  console.log(Object.values(Person));   // [ '张三', '男', [Function: run] ]
  for (let i of Object.values(Person)) {
    console.log(`${i}`);
  }
  • Object.freeze | Object.isFrozen
  //冻结一个对象。一个被冻结的对象再也不能被修改;
  //冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。
  //此外,冻结一个对象后该对象的原型也不能被修改。

  let student = {name: '李四', age: 37, grade: '初一', class: '二班'};
  Object.freeze(student);
  student.position = '三好学生';

  console.log(student);  // { name: '李四', age: 37, grade: '初一', class: '二班' }

  // 判断该对象是否为冻结对象
  console.log(Object.isFrozen(student));  //true  
  • Object.seal | Object.isSealed
  let student = {name: '李四', age: 37, grade: '初一', class: '二班'};

  //封闭一个对象,阻止添加新属性、阻止删除属性,及增删改不生效
  Object.seal(student);
  console.log(student);  // { name: '李四', age: 37, grade: '初一', class: '二班' }

  student['height'] = 100;
  console.log(student);  // { name: '李四', age: 37, grade: '初一', class: '二班' }
  
  delete student.class;
  console.log(student);  // { name: '李四', age: 37, grade: '初一', class: '二班' }

  //判断一个对象是否被密封
  console.log(Object.isSealed(student));  // true  
  • Object.observe:非标准,禁止在生产环境使用
  var obj = {};
  Object.observe(obj, function (changes) {
    changes.forEach(function (change) {
      console.log('变化的属性:  ' + change.name);
      console.log('变化的类型?: ' + change.type);
      console.log('旧值:  ' + change.oldValue);
      console.log('新值:  ' + change.object[change.name]);
    });
  });

Object.defineProperty

缺陷:无法通过下标方式修改数组数据或者给对象新增属性

  Object.defineProperty(
    obj,         // 要定义属性的对象
    prop,        // 要定义或修改的属性的名称或 Symbol 
    descriptor   // 要定义或修改的属性描述符。
  )  

  // descriptor
  {
    value: any, // [undefined] 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
    configurable: Boolean, // [false] 当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
    enumerable: Boolean, // [false] 当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
    writable: Boolean, // [false] 当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。
    get: Function, // [undefined]
    set: Function, // [undefined]
  }

代码示例

  async function Value() {
    let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});

    Object.defineProperty(School, 'name', {
      value: '张家顺',
      writable: false 
    });

    School.name = "李思凯";
    console.log(School.name);  //张家顺
  }


  // 属性描述符是否允许可写?
  async function Writable() {
    let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});

    Object.defineProperty(School, 'name', {
      value: '张家顺',
      writable: false 
    });

    try {
      School.name = "李思凯";
    } catch(e) {
      console.log(e);
    }
    console.log(School.name); //张家顺
  }


  // 属性是否允许出现在对象的枚举属性中?例如在 for...in 循环和 Object.keys() 中被枚举
  async function Enumerable() {
    let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});

    Object.defineProperty(School, 'name', {
      value: '张家顺',
      writable: true,
      enumerable: false
    });
    for (let i in School) {
      console.log(i + '=' + School[i]);
      //principal=李大钊
      //address=北京市
      //history=[object Object]
    }

    //如果对象的键-值都不可枚举,那么将返回由键组成的数组
    console.log(Object.keys(School));
  }


  // 表示对象的属性是否可以被删除?
  async function Configuration() {
    let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});

    Object.defineProperty(School, 'name', {
      value: '张家顺', 
      configuration: false
    });
    
    try {
      Object.defineProperty(School, 'name', {
        value: 'iu哦申达股份'
      });
    } catch(e) {
      console.log(e);
      //TypeError: Cannot redefine property: name
    }

    delete School.name;
    console.log(School);

  }


  // 自定义 Setters 和 Getters
  async function SettersGetters() {
    let School = Object.create({name: '北京大学', principal: '李大钊', address: '北京市', history: {}});

    let student = {};

    Object.defineProperty(student, 'name', {
      get() {
        return document.getElementById('container').innerHTML;
      },
      set(value) {
        document.getElementById('container').innerHTML = value;
      }
    });
    student.name = "张三";
    window.setTimeout(()=> {
      student.name = "李斯";
    }, 3000);
  }


  async function Structure() {
    let Students = {};

    Object.defineProperty(Students, 'name', {
      value: '',             //<String>
      writable: true,        //<Boolean>
      enumerable: true,      //<Boolean>
      configuration: true,   //<Boolean>
      set(value) {
        Students.name = value;
      },
      get() {
        return Students;
      }
    });

    Object.defineProperty(Student, 'name', {
      value: '张家顺',      //设置后不能设置get和set
      writable: true,      //当且仅当该属性的writable为true时,value才能被赋值运算符改变
      enumerable: true,    //是否可枚举?
      configuration: true  //可被改变或删除?
    });
  }  
  • Object.defineProperties
  let Nation = {};
  Object.defineProperties(Nation, {
    'province': {
      value: '贵州省',
      writable: true,
      enumerable: true,
      configurable: true
    },
    'city': {
      value: '毕节市',
      writable: true,
      enumerable: true,
      configurable: true
    },
    'country': {
      enumerable: true,
      configurable: true,
      set(value) {
        console.log('县: ' + value);
      },
      get() {
        return '大方县';
      }
    }
  });

  console.log(Nation);
  console.log(Nation.country);
  Nation.country = '织金县';  
  • Object.is(): 比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。
  Object.is('foo', 'foo');     // true
  Object.is(window, window);   // true

  Object.is('foo', 'bar');     // false
  Object.is([], []);           // false

  var foo = { a: 1 };
  var bar = { a: 1 };
  Object.is(foo, foo);         // true
  Object.is(foo, bar);         // false

  Object.is(null, null);       // true

  // 特例
  Object.is(0, -0);            // false
  Object.is(0, +0);            // true
  Object.is(-0, -0);           // true
  Object.is(NaN, 0/0);         // true
  • Set与Map的区别

set是一种关联式容器,其特性如下:

set以RBTree作为底层容器 所得元素的只有key没有value,value就是key 不允许出现键值重复 所有的元素都会被自动排序 不能通过迭代器来改变set的值,因为set的值就是键

map和set一样是关联式容器,它们的底层容器都是红黑树,区别就在于map的值不作为键,键和值是分开的。它的特性如下:

map以RBTree作为底层容器 所有元素都是键+值存在 不允许键重复 所有元素是通过键进行自动排序的 map的键是不能修改的,但是其键对应的值是可以修改的

ES6

ES6内容

let 与 const 解构赋值 Symbol Map 与 Set Reflect 与 Proxy 字符串 数值 对象 数组 函数 迭代器 Class 类 模块 Promise 对象 Generator 函数 async 函数 for...of...

迭代器(Iterators)

生成器(generator)

/**
 * 迭代器(Iterators)
 * 迭代器允许每次访问数据集合的一个元素,当指针指向数据集合最后一个元素是,迭代器便会退出。它提供了 next() 函数来遍历一个序列,这个方法返回一个包含 done 和 value 属性的对象。
 * ES6 中可以通过 Symbol.iterator 给对象设置默认的遍历器,无论什么时候对象需要被遍历,执行它的 @@iterator 方法便可以返回一个用于获取值的迭代器。
 * 可以通过 [Symbol.iterator]() 自定义一个对象的迭代器
 */
var arr = [11,12,13];
var itr = arr[Symbol.iterator]();
 
itr.next(); // { value: 11, done: false }
itr.next(); // { value: 12, done: false }
itr.next(); // { value: 13, done: false }
 
itr.next(); // { value: undefined, done: true }


/**
 * 生成器( generator)
 * 语法:function *generatorName() {yield 1; ...; yield n;}
 * 功能:返回一个迭代器的函数;
 * obj.next().value:获取值;
 * obj.next().done:判断是否已停止提供值。
 */
function *createIterator() {
	yield 1;
	yield 2;
	yield 3;
}
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().done);  //false
console.log(iterator.next().value); // 3
console.log(iterator.next().value); // undefined
console.log(iterator.next().done);  //true

Map与WeakMap

存储键值对

一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是[任意值]。
Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

  • 劣势:增删改查的性能

当数据量不高于百万级别时,使用Map处理数据,性能会更好;
当数据量大于百万级别时,使用Object处理数据,性能会更好。

Map对象

map.clear() – 移除 Map 对象的所有键/值对 。 map.set() – 设置键值对,返回该 Map 对象。 map.get() – 返回键对应的值,如果不存在,则返回 undefined。 map.has() – 返回一个布尔值,用于判断 Map 中是否包含键对应的值。 map.delete() – 删除 Map 中的元素,删除成功返回 true,失败返回 false。 map.size – 返回 Map 对象键/值对的数量。 map.keys() - 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。 map.values() – 返回一个新的Iterator对象,包含了Map对象中每个元素的值 。

const map = new Map();
map.set('name', 'zhangsan');  // 设置键值
console.log(map.get('name')); // 获取键值
console.log(map.size);        // 获取键长度
console.log(map.has(key));    // 查找键名
  • Map 对象的操作

Map 与 Array的转换

var kvArray = [["key1", "value1"], ["key2", "value2"]];  
// Map 构造函数可以将一个 二维 键值对数组转换成一个 Map 对象  
var myMap = new Map(kvArray);  
// 使用 Array.from 函数可以将一个 Map 对象转换成一个二维键值对数组  
var outArray = Array.from(myMap); 
  • Map 的克隆
var myMap1 = new Map([["key1", "value1"], ["key2", "value2"]]);  
var myMap2 = new Map(myMap1);  
console.log(original === clone);   
// 打印 false。 Map 对象构造函数生成实例,迭代出新的对象。 
  • Map 的合并
var first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],]);  
var second = new Map([[1, 'uno'], [2, 'dos']]);  
// 合并两个 Map 对象时,如果有重复的键值,则后面的会覆盖前面的,对应值即 uno,dos, three  
var merged = new Map([...first, ...second]); 

WeakMap

作为弱引用的Map, WeakMap 中的东西垃圾回收时不考虑,使用它不用担心内存泄漏问题。且不可枚举
delete(key),has(key),get(key) 和set(key, val)
WeakMap 的所有 key 必须是对象

const wk = new WeakMap();

目的:传统对象添加了值后形成了引用,一旦不再需要这两个对象,必须手动删除这个引用,否则垃圾回收机制不会释放,造成内存溢出。
应用场景:举个例子,在一个带分页table列表里,每一列的查看功能需要向后端请求数据并显示,我们需要对这个点击操作做缓存,但又需要当翻页后或者离开页面,即列表里的数据消失时就清除掉这些缓存,方式缓存过多造成内存浪费。那么这个时候我们用weakMap就是最好的选择。

  • Map与WeakMap的区别?

与Map的API区别在于没有key(),entries(),clear()和size

new Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

/**
 * 资源
 * https://www.runoob.com/w3cnote/es6-reflect-proxy.html
 * https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
 * 
 * 定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)
 */
// 结构
let proxy = new Proxy({}, {
  set(Target, Property, Value) {},
  get(Target, Property) {}
});

let p = new Proxy(Target, Handler);
/**
 * Target:目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
 * Handler:一个对象,声明了代理 target 的指定行为, 其属性是当执行一个操作时定义代理的行为的函数。
 */
set(Target, Property, Value)
get(Target, Property)


// 示例
let proxy = new Proxy({}, {
  set(Target, Property, Value) {
    console.log(Target);    // {}
    console.log(Property);  // name
    console.log(Value);     // Ysun
  },
  get(Target, Property) {
    console.log(Target);    // {}
    console.log(Property);  // name
  }
});

proxy.name = 'Ysun';
proxy.name;


get(target, propKey, receiver);
let proxy = new Proxy({}, {
  get(target, propKey, receiver) {
    // 实现私有属性读取保护
    if(propKey[0] === '_'){
        throw new Erro(`Invalid attempt to get private     "${propKey}"`);
    }
    console.log('Getting ' + propKey);
    return target[propKey];
  }
});
 
let obj = Object.create(proxy);
obj.name
// Getting name


set(target, propKey, value, receiver)
let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }
    // 对于满足条件的 age 属性以及其他属性,直接保存
    obj[prop] = value;
  }
};
let proxy= new Proxy({}, validator)
proxy.age = 100;
proxy.age           // 100
proxy.age = 'oppps' // 报错
proxy.age = 300     // 报错


// Proxy 代理对象,自定义代理对象属性与行为,即拦截对象
let Students = new Proxy({}, {
  set: function(target, key, value) {
    console.log('Set');
  },
  get: function(target, key, value) {
    console.log('Get'); 
  }
});

Students.total = 10000;  //Set
console.log(Students.total);  //Get

ES6

变量声明let和const

let:声明变量,并拥有块级作用域; const:声明常量,并拥有块级作用域。

const {
  name,
  sex: otherSex
} = object;

类class

class Block {
  constructor() {
    this.name = '区块链';  
  }  
  add() {
    console.log('添加账本');
  } 
}

// 继承
class Line extends Point {
  // ES6 要求,子类的构造函数必须执行一次 super 函数,否则会报错
  constructor() { 
    // 子类 constructor 方法中必须有 super ,且必须出现在 this 之前。
    super();
  
    console.log(super); // super指向父类this
    console.log(this);  // this指向子类
  }
}

继承常规对象

let Point = {};
Object.setPrototypeOf(Child.prototype, Point);

模板字符串

字符串格式化:${}

let name = `12345`;
console.log(`hello ${name}`);

拼接字符串:``

let template = `<div>
  <span>123456</span>
</div>`
console.log(template);

函数-默认带参数

功能:定义函数时便初始化了这个参数,以便在参数没有被传递进去时使用;

function action(a = 100) {
  console.log(a);
}
action(); //100
action(10); //10

箭头函数

当你的函数有且仅有一个参数的时候,是可以省略掉括号的。当你函数返回有且仅有一个表达式的时候可以省略{};

console.log([0, 2, 7].map((key) => { return key > 2 }));
console.log([0, 2, 7].map((key) => key > 2 ));
  • 对象-键值对重名
function getData() {
  retrun {
    name,
    age
  }
}
  • 对象-省略冒号与 function 关键字
let add = {
  name: 'zhang',
  get() {
    console.log(this.name);
  }
};
add.get();  //zhang
  • 数据访问--解构
let people = {
  total: 30,
  boy: 12,
  girl: 18,
  change (x) {
    return x * 1;
  }
};
const {total, boy} = people;
console.log(`${total} --- ${boy}`);

const color = ['red', 'blue']
const [first, second] = color;
console.log(first);  //'red'
console.log(second);  //'blue'
  • Spread Operator 展开运算符...

组装数组

const color = ['red', 'yellow'];
const colorful = [...color, 'green', 'pink'];
console.log(colorful);  //['red', 'yellow', 'green', 'pink']

组装对象

const alp = { fist: 'a', second: 'b'};
const alphabets = {...alp, third: 'c'};
console.log(alphabets);   //{ "fist": "a", "second": "b", "third": "c"}

获取数组除了前几项或者除了某几项的其他项

const number = [1,2,3,4,5]
const [first, ...rest] = number;
console.log(rest);   //[2,3,4,5]

获取对象除了前几项或者除了某几项的其他项

const user = {
  username: 'lux',
  gender: 'female',
  age: 19,
  address: 'peking'
}
const {username, ...rest} = user;
console.log(rest); //{gender: "female", age: 19, address: "peking"}

组合成新的 Object,如果有重复的属性名,右边覆盖左边

const first = {
  a: 1,
  b: 2,
  c: 6,
};
const second = {
  c: 3,
  d: 4
};
const total = {...first, ...second};
console.log(total);  //{a: 1, b: 2, c: 3, d: 4}
  • Rest 操作符

当被用于函数传参时,是一个 Rest 操作符

function foo(...args) {
  console.log(args);
}
foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
  • 对象词法扩展

ES6 允许声明在对象字面量时使用简写语法,来初始化属性变量和函数的定义方法,并且允许在对象属性中进行计算操作

module.exports = {
  name,
  add
}
  • 模板语法和分隔符
let name = `hello ${name} world`;
  • babel-polyfill
import Promise from 'promise-polyfill';
// To add to window  解决promise 在ie中未定义的问题
if (!window.Promise) {
  window.Promise = Promise;
}

require("babel-polyfill");
import "babel-polyfill";

module.exports = {
  entry: ["babel-polyfill", "./app/js"]
};
  • Symbol

ES6 中提出 symbol 的目的是为了生成一个唯一的标识符,不过你访问不到这个标识符 Symbol 是一种新的数据类型,它的值是唯一的,不可变的

var sym = Symbol( "some optional description" );
console.log(typeof sym); // symbol

Object.getOwnPropertySymbols(o) 获取对象 symbol 属性

Set与WeakSet

Set 对象是一组不重复的值,重复的值将被忽略,值类型可以是原始类型和引用类型
无重复值的有序列表

  • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set
  • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet

创建对象

let set new Set();

基础语法

添加元素:set.add(VALUE);
删除指定序列元素:set.delete(index);
清空元素:set.clear();
查找值是否存在:set.has(VALUE);

数组去重

let array = [0,3,1,3];  
let queue = new Set(array);  
console.log([...queue]);  //0,3,1  
  • 类型转换

Array

  • Array 转 Set
var mySet = new Set(["value1", "value2", "value3"]);
  • 用...操作符,将 Set 转 Array
var myArray = [...mySet];

String 转 Set

var mySet = new Set('hello');  // Set(4) {"h", "e", "l", "o"}

注:Set 中 toString 方法是不能将 Set 转换成 String

Set转换为Array

Array.from(array);

Array转换为Set

new Set(Array);

遍历

for (let item of queue.keys()) {  
  console.log();    
}  
for (let item of queue.values()) {  
  console.log();    
}  
for (let item of queue.entries()) {  
  console.log();    
} 

WeakSet

类似于 WeakMap,WeakSet 对象可以让你在一个集合中保存对象的弱引用,在 WeakSet 中的对象只允许出现一次
Weak Set构造器不接受基本类型数据,只接受对象。同样的可以使用可迭代的对象如数组,来作为构造器参数,来创建Weak Set

WeakSet与Set之间的差异

对于Weak Set实例,若调用了add()方法时传入了非对象的参数,则会抛出错误。如果在has()或者delete()方法中传入了非对象的参数则会返回false;
Weak Set不可迭代,因此不能用于for-of循环;
Weak Set 无法暴露出任何迭代器(例如 keys() 与 values() 方法) ,因此没有任何编程手段可用于判断 Weak Set 的内容;
Weak Set没有forEach()方法;
Weak Set没有size属性;

Set 对象

Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用

Set 中的特殊值:Set 对象存储的值总是唯一的,所以需要判断两个值是否恒等。有几个特殊值需要特殊对待

+0 与 -0 在存储判断唯一性的时候是恒等的,所以不重复;
undefined 与 undefined 是恒等的,所以不重复;
NaN 与 NaN 是不恒等的,但是在 Set 中只能存一个,不重复。

let mySet = new Set();  
 
mySet.add(1); // Set(1) {1}  
mySet.add(5); // Set(2) {1, 5}  
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性  
mySet.add("some text"); 
  • Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = {a: 1, b: 2};   
mySet.add(o);  
mySet.add({a: 1, b: 2}); 
  • Set(5) {1, 5, "some text", {…}, {…}}
  • 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储

Set 对象作用

数组去重

var mySet = new Set([1, 2, 3, 4, 4]);  
[...mySet]; // [1, 2, 3, 4]

并集

var a = new Set([1, 2, 3]);  
var b = new Set([4, 3, 2]);  
var union = new Set([...a, ...b]); // {1, 2, 3, 4}  

交集

var a = new Set([1, 2, 3]);  
var b = new Set([4, 3, 2]);  
var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3} 

差集

var a = new Set([1, 2, 3]);  
var b = new Set([4, 3, 2]);  
var difference = new Set([...a].filter(x => !b.has(x))); // {1} 

Symbol

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名; Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一个字符串作为参数,为新创建的 Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区分。

  • https://developer.mozilla.org/zh-CN/docs/Glossary/Symbol

作为属性名

由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。
Symbol 值作为属性名时,该属性是公有属性不是私有属性,可以在类的外部访问。 但是不会出现在 for...in 、 for...of 的循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回。 如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到。

  let sy = Symbol("key1");  
  let syObject = {};  
  syObject[sy] = "kk";  
  console.log(syObject);    // {Symbol(key1): "kk"}    

  let syObject = {};  
  Object.defineProperty(syObject, sy, {value: "kk"});  
  console.log(syObject);   // {Symbol(key1): "kk"}  

定义常量

  const COLOR_RED = Symbol("red");
  const COLOR_YELLOW = Symbol("yellow");
  const COLOR_BLUE = Symbol("blue");  
  • Symbol.for():类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。
  let yellow = Symbol("Yellow");  
  let yellow1 = Symbol.for("Yellow");  
  yellow === yellow1;      // false  
  
  let yellow2 = Symbol.for("Yellow");  
  yellow1 === yellow2;     // true    
  • Symbol.keyFor():返回一个已登记的 Symbol 类型值的 key ,用来检测该字符串参数作为名称的 Symbol 值是否已被登记。
  let yellow1 = Symbol.for("Yellow");  
  Symbol.keyFor(yellow1);    // "Yellow"  

Reflect

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。

注意事项

Reflect不是一个函数对象,因此它是不可构造的。

ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上。 Reflect 对象对某些方法的返回结果进行了修改,使其更合理。 Reflect 对象使用函数的方式实现了 Object 的命令式操作。

Reflect.get(target, name, receiver)

target:目标对象 name:属性 receiver:当 target 对象中存在 name 属性的 getter 方法, getter 方法的 this 会绑定 receiver 示例

  let exam = {
    name: "Tom",
    age: 24,
    get info() {
      return this.name + this.age;
    }
  }
  console.log(Reflect.get(exam, 'name'));  //Tom

  // 当 target 对象中存在 name 属性的 getter 方法, getter 方法的 this 会绑定 // receiver
  let receiver = {
    name: "Jerry",
    age: 20
  }
  console.log(Reflect.get(exam, 'info', receiver));  //Jerry20

Reflect.set(target, name, value, receiver)

将 target 的 name 属性设置为 value。返回值为 boolean ,true 表示修改成功,false 表示失败。当 target 为不存在的对象时,会报错。 当 target 对象中存在 name 属性 setter 方法时,setter 方法中的 this 会绑定 // receiver , 所以修改的实际上是 receiver 的属性

  let exam = {
    name: "Tom",
    age: 24,
    set info(value){
      return this.age = value;
    }
  }
  let receiver = {
    age: 18
  }
  let result = Reflect.set(exam, 'info', 1, receiver); 
  console.log(result);  // true
  • Reflect.has()

用于查找 name 属性在 obj 对象中是否存在。返回值为 boolean

  let exam = {
    name: "Tom",
    age: 24
  }
  Reflect.has(exam, 'name'); // true

Reflect.deleteProperty(obj, property)

是 delete obj[property] 的函数化,用于删除 obj 对象的 property 属性,返回值为 boolean。如果 obj 不是对象则会报错 TypeError

  let exam = {
    name: "Tom",
    age: 24
  }
  Reflect.deleteProperty(exam , 'name'); // true
  exam // {age: 24} 
  # property 不存在时,也会返回 true
  Reflect.deleteProperty(exam , 'name'); // true

Reflect.construct(obj, args)

等同于 new target(...args)

  function exam(name){
    this.name = name;
  }
  Reflect.construct(exam, ['Tom']); // exam {name: "Tom"}

Reflect.getPrototypeOf(obj)

用于读取 obj 的 proto 属性。在 obj 不是对象时不会像 Object 一样把 obj 转为对象,而是会报错

  class Exam{}
  let obj = new Exam()
  Reflect.getPrototypeOf(obj) === Exam.prototype // true

Reflect.setPrototypeOf(obj, newProto)

用于设置目标对象的 prototype

let obj ={}
Reflect.setPrototypeOf(obj, Array.prototype); // true

Reflect.apply(func, thisArg, args)

等同于 Function.prototype.apply.call(func, thisArg, args) func 表示目标函数;thisArg 表示目标函数绑定的 this 对象;args 表示目标函数调用时传入的参数列表,可以是数组或类似数组的对象。 若目标函数无法调用,会抛出 TypeError 。

Reflect.apply(Math.max, Math, [1, 3, 5, 3, 1]); // 5

Reflect.defineProperty(target, propertyKey, attributes)

于为目标对象定义属性。如果 target 不是对象,会抛出错误

let myDate= {}
Reflect.defineProperty(MyDate, 'now', {
  value: () => Date.now()
}); // true
 
const student = {};
Reflect.defineProperty(student, "name", {value: "Mike"}); // true
student.name; // "Mike"

Reflect.getOwnPropertyDescriptor(target, propertyKey)

用于得到 target 对象的 propertyKey 属性的描述对象。在 target 不是对象时,会抛出错误表示参数非法,不会将非对象转换为对象。

var exam = {}
Reflect.defineProperty(exam, 'name', {
  value: true,
  enumerable: false,
})
Reflect.getOwnPropertyDescriptor(exam, 'name'); //{ configurable: false, enumerable: false, value: true, writable: false}
// propertyKey 属性在 target 对象中不存在时,返回 undefined
Reflect.getOwnPropertyDescriptor(exam, 'age') // undefined

Reflect.isExtensible(target)

用于判断 target 对象是否可扩展。返回值为 boolean 。如果 target 参数不是对象,会抛出错误。

let exam = {}
Reflect.isExtensible(exam) // true

Reflect.preventExtensions(target)

用于让 target 对象变为不可扩展。如果 target 参数不是对象,会抛出错误。

let exam = {}
Reflect.preventExtensions(exam) // true

Reflect.ownKeys()

返回对象所有的属性,不管属性是否可枚举,包括 Symbol 用于返回 target 对象的所有属性,等同于 Object.getOwnPropertyNames 与Object.getOwnPropertySymbols 之和

var exam = {
  name: 1,
  [Symbol.for('age')]: 4
}
let result = Reflect.ownKeys(exam);  // ["name", Symbol(age)]
for (let i of result) {
  console.log(i);
}
  • 为不具备 Iterator 接口的对象提供遍历方法
function* objectEntries(obj) {
  const propKeys = Reflect.ownKeys(obj);
  for (const propKey of propKeys) {
    yield [propKey, obj[propKey]];
  }
}

const jane = { first: 'Jane', last: 'Doe' };
for (const [key,value] of objectEntries(jane)) {
  console.log(`${key}: ${value}`);
}
Last Updated:
Contributors: 709992523, Eshen