对象

131 阅读4分钟

对象方法

Object.getOwnPropertyDescriptor

ES5 方法

let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
//    value: 123,
//    writable: true,
//    enumerable: true,
//    configurable: true
//  }
描述对象的enumerable属性,称为“可枚举性”,如果该属性为false,就表示某些操作会忽略当前属性。

Object.getPrototypeOf

使用Object.getPrototypeOf()可以方便地取得一个对象的原型

Object.is

ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

+0 === -0 //true
NaN === NaN // false

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

Object.assign

方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

第一个参数是目标对象,后面的参数都是源对象

检测属性的方法

in运算符、hasOwnPreperty()和propertyIsEnumerable()

  • in:对象的自有属性或者继承属性返回true,不考虑是否可枚举
var o={x:1} 
"x"in o;//true"x"是o的属性 
"y"in o;//false"y"不是o的属性 
"toString"in o;//true:o继承toString属性

  • hasOwnPreperty:仅检测到自有属性返回true
var o={x:1} 
o.hasOwnProperty("x");//true:o有一个自有属性x 
o.hasOwnProperty("y");//false:o中不存在属性y
o.hasOwnProperty("toString");//false:toString是继承属性
  • propertyIsEnumerable:只有检测到是自有属性且属性可枚举时它才返回true。

遍历属性的方法

  • ==for...in==循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
  • ==Object.keys==返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名
  • ==Object.getOwnPropertyNames==返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名
  • ==Object.getOwnPropertySymbols==返回一个数组,包含对象自身的所有 Symbol 属性的键名
  • ==Reflect.ownKeys==返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。

其他方法

  • Object.values()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
  • Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组

创建对象和ES6的Class

1. 工厂模式

代码:

function createPerson(name,age,job) {
    var o = newObject();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    };
    return o;
}
var person1 = createPerson ("Nicholas",29,"SoftwareEngineer");
var person2 = createPerson("Greg",27,"Doctor");

解决了创建多个相似对象的问题,但却没有解决对象识别的问题

2. 构造器模式

特点:

  1. 没有显示的创建对象
  2. 直接将属性和方法赋给this
  3. 没有return

new的过程

  1. 创建一个新的对象
  2. 将构造函数的作用域赋给新对象,即改变this指向,指向新对象
  3. 执行构造函数中的代码(给新对象添加属性和方法)
  4. 返回新对象
/**
 * 构造函数
 */

function Person(name, age, job) { 
  this.name = name; 
  this.age = age; 
  this.job = job; 
  this.sayName = function () { alert(this.name); };
  // 与声明函数在逻辑上是等价的,
  // 导致每次new一个对象时都会创建新的sayName
  this.sayName = newFunction("alert(this.name)");

  this.sayNameFunc = sayNameFunc;
} 

// 该方式导致作用域混乱
function sayNameFunc(){ alert(this.name); }

var person1 = newPerson("Nicholas", 29, "SoftwareEngineer");
var person2 = newPerson("Greg", 27, "Doctor");
console.log(person1.sayName === person2.sayName); // false

问题:

对于方法的创建比较麻烦,1、如果在构造函数内部直接赋值到this,会造成每次new时都创建一个新Function的情况;2、如果将函数声明放到外部,又会出现作用域问题。

3. 原型模式(构造函数+原型)

构造函数+原型

  • 每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象
  • 这个对象的用途是==包含==可以由特定类型的所有==实例共享==的属性和方法。

4. ES6的Class

  • ES6 的类,完全可以看作构造函数的另一种写法。
  • 类的数据类型就是函数,类本身就指向构造函数
  • 类的所有方法都定义在类的prototype属性上面。
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}
  • constructor: 构造方法
  • this:实例对象
class Person {
  constructor(){
    console.log(this.__proto__.constructor === Person); // ture
  }
}

const person1 = new Person();
console.log(person1.constructor === Person.prototype.constructor); // true
console.log(person1.__proto__.constructor === Person.prototype.constructor); // true
console.log(person1.__proto__.constructor === Person); // true
console.log(person1.__proto__.constructor.prototype === Person.prototype); // true
console.log(Person === Person.prototype.constructor); // true