Skip to content
本页目录

Object 对象

构造函数

JS
Object()
Object()
JS
Object.prototype.constructor === Object

Object.__proto__ === Function.prototype
Object.prototype.constructor === Object

Object.__proto__ === Function.prototype

属性

  • name
  • length
  • __proto__:指向对象的构造函数原型对象
  • constructor:指向该对象的构造函数

方法

方法说明返回值
Object.is(obj1, obj2)比较两个值是否相等,取代 === 的缺陷boolean
Object.create(obj)传入值为 null 为不继承
assign()对象的合并
freeze()
isFronze()
seal()
isSealed()
keys()
values()
entries()将一个键值对数组转为对象,不含继承属性
defineProperty()Vue2 数据劫持的实现方法
defineProperties()boolean
obj1.prototype.isPrototypeOf(obj2)判断 obj1 是否为 obj2 的原型
Object.getPrototypeOf(obj)读取一个对象的原型对象对象的原型
Object.setPrototypeOf(obj1, obj2)obj1 隐性原型指向 obj2
Object.hasOwn(obj, prop)ES6 是否为自身可遍历属性,静态方法
obj.hasOwnProperty(prop)是否为自身可遍历属性,原型方法,有缺陷boolean
obj.propertyIsEnumerable(prop)是否为自身可遍历可枚举属性boolean
getOwnPropertyNames()
Object.getOwnPropertyDescriptor()ES5对象某个属性的描述对象
Object.getOwnPropertyDescriptors()ES2017 不含继承属性对象所有属性的描述对象
getOwnPropertySymbols()
toString()
valueOf()
apply()
call()
bind()
constructor指向该对象的构造函数
__proto__读取或设置当前对象的原型对象 prototype
__defineGetter__
__defineSetter__

遍历

方法参数说明返回值
for...in
keys新数组
values新数组
entries

注意:Object 默认是不支持 for...of 遍历的,因为其没有部署 Symbol.Iterator 接口

判断属性是自身的还是继承的

JS
foo.hasOwnProperty('bar') // ES5
Object.hasOwn(foo, 'a') // ES6
foo.hasOwnProperty('bar') // ES5
Object.hasOwn(foo, 'a') // ES6
检测方法不可枚举属性继承属性
in
has()
hasOwnProperty()××
propertyIsEnumerable()×
hasOwn()××
  • hasinES6 替代方案,是为了写法统一挂载到对象的静态方法
  • hasOwn()hasOwnProperty()ES6+ 替代方案,hasOwnProperty() 有一些缺点

setPrototypeOf() 与 getPrototypeOf()

Object.setPrototypeOf 方法的作用与 __proto__ 相同,用来设置一个对象的原型对象(prototype),返回参数对象本身。
因为 __proto__ 规范只要去其在浏览器中要部署,所以标准增加了这个方法用于取代 __proto__ 写法。

  • Object.create():生成操作
  • Object.getPrototypeOf(obj):读操作
  • Object.setPrototypeOf():写操作
JS
function setPrototypeOf(obj1, obj2) {
  obj1.__proto__ = obj2;
  return obj1;
}
function setPrototypeOf(obj1, obj2) {
  obj1.__proto__ = obj2;
  return obj1;
}

对象属性简写

JS
const o = {
  method() {
    return "Hello!";
  }
};
// 等同于
const o = {
  method: function() {
    return "Hello!";
  }
};
const o = {
  method() {
    return "Hello!";
  }
};
// 等同于
const o = {
  method: function() {
    return "Hello!";
  }
};

Object.assign 方法

主要用来合并对象:Object.assign(target, source1, source2);

注意点

  • 同名属性,后面会覆盖前面
  • Object 类型会被转为 Object 再合并
  • 无法合并 undefinednull,因为它们无法被转为对象
  • 实现的是浅拷贝
  • 可以处理数组,但会当为对象处理,即下标一致会被覆盖

常用场景

  • 为对象添加属性
JS
class Point {
  constructor(x, y) {
    Object.assign(this, {x, y});
  }
}
class Point {
  constructor(x, y) {
    Object.assign(this, {x, y});
  }
}
  • 为对象添加方法
JS
Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2) {
    // ···
  },
  anotherMethod() {
    // ···
  }
});
Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2) {
    // ···
  },
  anotherMethod() {
    // ···
  }
});
  • 对象合并
  • 浅拷贝
  • 为对象属性设置默认值(组件中常用)

super 关键字

扩展运算符

...

链判断运算符

?.

题目

1. new 操作符具体干了什么呢?

  1. 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型(prototype)。
  2. 属性和方法被加入到 this 引用的对象中。
  3. 新创建的对象由 this 所引用,并且最后隐式的返回 this

红宝书说法

  1. 创建一个新对象;
  2. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
  3. 执行构造函数中的代码(为这个新对象添加属性);
  4. 返回新对象
js
// 函数并未显式接受参数,而是通过内部 arguments 接收
function _new() {
    var obj = new Object(); 

    // 取出第一个参数,也就是传入的需要被实例化的函数
    // [].shift.call(arguments) 等价于 Array.prototype.shift.call(arguments)
    // 其返回值是第一个参数,也就是传入的方法,剩下的arguments已经不包含第一个参数了
    Constructor = [].shift.call(arguments);

    // 将对象的隐性原型指向传入函数的显式原型
    obj.__proto__ = Constructor.prototype;

    // 将参数传给传入的函数,并执行
    var result = Constructor.apply(obj, arguments);
    
    // 注意 null 与 function 情况
    if((result && typeof result === 'object') || typeof result === 'function') {
      return result;
    } else {
      return obj;
    }
};
// 函数并未显式接受参数,而是通过内部 arguments 接收
function _new() {
    var obj = new Object(); 

    // 取出第一个参数,也就是传入的需要被实例化的函数
    // [].shift.call(arguments) 等价于 Array.prototype.shift.call(arguments)
    // 其返回值是第一个参数,也就是传入的方法,剩下的arguments已经不包含第一个参数了
    Constructor = [].shift.call(arguments);

    // 将对象的隐性原型指向传入函数的显式原型
    obj.__proto__ = Constructor.prototype;

    // 将参数传给传入的函数,并执行
    var result = Constructor.apply(obj, arguments);
    
    // 注意 null 与 function 情况
    if((result && typeof result === 'object') || typeof result === 'function') {
      return result;
    } else {
      return obj;
    }
};

ES6 语法实现

JS
function _new(fn, ...args){
    const obj = Object.create(fn.prototype);
    const result = fn.apply(obj, args);
    // 如果函数返回 非空并是对象 返回 value 否则 返回 obj
    return result instanceof Object ? result : obj;
}
function _new(fn, ...args){
    const obj = Object.create(fn.prototype);
    const result = fn.apply(obj, args);
    // 如果函数返回 非空并是对象 返回 value 否则 返回 obj
    return result instanceof Object ? result : obj;
}

使用:

JS
function Person(name, age) {
  this.name = name;
  this.age = age;
}

let person = _new(Person, 'zhang', 18);
function Person(name, age) {
  this.name = name;
  this.age = age;
}

let person = _new(Person, 'zhang', 18);

2. 字面量 {} 、new Object() 与 Object.create() 的区别

  • 字面量与 new Object() 创建的对象是一样的,都是 Object 对象的实例,其 __proto__ === Object.prototype ,继承了内置对象 Object
  • Object.create() 方法创建的对象,一般与上面方式一样,只有当传入的参数为 null 时,其将不会继承 Object 的属性与方法

Object.create() 方法在 ES6 之前经常被用来实现继承。

JS
function Shape() {
  this.x = 0;
  this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// subclass extends superclass
// 创建一个继承自 Shape 的对象
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

const rect = new Rectangle();

rect.move(1, 1); // Outputs, 'Shape moved.'
function Shape() {
  this.x = 0;
  this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // call super constructor.
}

// subclass extends superclass
// 创建一个继承自 Shape 的对象
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

const rect = new Rectangle();

rect.move(1, 1); // Outputs, 'Shape moved.'

3. == === Object.is() 三种类型比较的区别

  • == 会先进行类型转换
  • === 无法比较 NaN+0、-0
  • Object.is(a, b) 为了解决 === 存在的问题

4. prototype__proto__constructor 三者的区别

  • __proto__constructor 属性是对象所独有的
  • prototype 属性是函数所独有的
  • 因为在 JS 中函数也是一种对象,所以函数也拥有 __proto__constructor 属性

5. __proto__

__proto__ 属性是由一个对象指向一个对象,即指向它们的原型对象/父对象。

作用:当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的 __proto__ 属性所指向的那个对象(可以理解为父对象)里找,如果父对象也不存在这个属性,则继续往父对象的 __proto__ 属性所指向的那个对象里找,如果还没找到,则继续往上找…直到原型链顶端 null,以上这种通过 __proto__ 属性来连接对象直到 null 的链型查找方式就是原型链

6. prototype

函数独有,它是从一个函数指向一个对象。它的含义是函数的原型对象。返回对象类型原型的引用。

作用:让该函数实例化的对象都可以继承函数的所有属性与方法。
任何函数在创建的时候,会默认同时创建该函数的 prototype 对象。

function 定义的对象有一个 prototype 属性,prototype 属性又指向了一个 prototype 对象,注意 prototype 属性与 prototype 对象是两个不同的东西,注意区别。在 prototype 对象中又有一个 constructor 属性,这个 constructor 属性同样指向一个 constructor 对象,而这个 constructor 对象恰恰就是这个 function 函数本身。

JS
function Fn() {}

new Fn().__proto__ === Fn.prototype

Fn.prototype.constructor === Fn

Fn.prototype.__proto__ === Object.prototype
function Fn() {}

new Fn().__proto__ === Fn.prototype

Fn.prototype.constructor === Fn

Fn.prototype.__proto__ === Object.prototype

7. constructor

constructor 属性也是对象才拥有的,它是从一个对象指向一个函数,返回创建此对象的函数的引用。

作用:指向该对象的构造函数,每个对象都有构造函数。

constructor 属性是专门为 function 而设计的,它存在于每一个 functionprototype 属性中,这个 constructor 保存了指向 function 的一个引用。

综合

JS
function A(){
    
}

let b = "字符串";
let c = new A();

// 输出该属性
console.log(b.__proto__); // String {'', constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}
console.log(c.__proto__); // {constructor: ƒ}
console.log(c.__proto__ === A.prototype); // true

// 将prototype展开的构造函数就是A本身也是c的构造函数
A.prototype.constructor === A === c.constructor

c.__proto __ === c.constructor.prototype === A.prototype
function A(){
    
}

let b = "字符串";
let c = new A();

// 输出该属性
console.log(b.__proto__); // String {'', constructor: ƒ, anchor: ƒ, big: ƒ, blink: ƒ, …}
console.log(c.__proto__); // {constructor: ƒ}
console.log(c.__proto__ === A.prototype); // true

// 将prototype展开的构造函数就是A本身也是c的构造函数
A.prototype.constructor === A === c.constructor

c.__proto __ === c.constructor.prototype === A.prototype

Function instanceof ObjectObject instanceof Function 原因

JS
Function.__proto__.__proto__ === Object.prototype

Object.__proto__ === Function.prototype
Function.__proto__.__proto__ === Object.prototype

Object.__proto__ === Function.prototype