跳到主要内容

all

2023年06月08日
柏拉文
越努力,越幸运

Object()


ObjectJavaScript的一种 数据类型 。它用于存储各种键值集合和更复杂的实体。Objects可以通过 **Object()**构造函数或者使用 对象字面量 的方式创建。Object构造函数为给定的参数创建一个包装类对象(object wrapper),具体有以下情况:

  • 如果给定值是 null 或 undefined,将会创建并返回一个空对象
  • 如果传进去的是一个基本类型的值,则会构造其包装类型的对象
  • 如果传进去的是引用类型的值,仍然会返回这个值,经他们复制的变量保有和源对象相同的引用地址

语法:

let num = 123;
let numObj1 = new Number(num); // 通过 new Number() 转换成类型对象
console.log(numObj1); // 结果为 Number {123}
let numOjb2 = Object(num); // 通过 Object() 转换成类型对象
console.log(numOjb2); // 结果为 Number {123}

let str = 'abc';
let strObj1 = new String(str); // 通过 new String() 转换成类型对象
console.log(strObj1); // 结果 String {'abc'}
let strObj2 = Object(str); // 通过 Object() 转换成类型对象
console.log(strObj2); // 结果 String {'abc'}

let bool = true;
let boolObj1 = new Boolean(bool); // 通过 new Boolean() 转换成类型对象
console.log(boolObj1); // 结果 Boolean {true}
let boolObj2 = Object(bool); // 通过 Object() 转换成类型对象
console.log(boolObj2); // 结果 Boolean {true}

Object.assign()


Object.assign() 方法用于从一个或多个源对象拷贝自身可枚举的属性(String属性Symbol属性),并且覆盖目标对象的同名属性。将所有可枚举属性的值分配到目标对象。它将返回目标对象。 **Object.assign()**中的目标对象不可以是null或者undefined,否则会报错。**Object.assign()**中的源对象对象如果是null或者undefined,会直接跳过。

语法

Object.assign(target, ...sources)
  • target: 目标对象。
  • sources: 源对象。

返回值

目标对象。

应用场景

  • 拷贝对象: 拷贝源对象自身可枚举的属性(String属性和Symbol属性),并且覆盖目标对象的同名属性。

    const s1Symbol = Symbol('s1');
    const s2Symbol = Symbol('s2');
    const obj1 = {
    type1:'obj1',
    [s1Symbol]:'s1Symbol'
    }
    Object.defineProperty(obj1,'value1',{
    value:'哈哈',
    writable:true,
    enumerable:false,
    configurable:true
    });
    const obj2 = {
    type2:'obj2',
    [s2Symbol]:'s2Symbol'
    }
    Object.defineProperty(obj2,'value2',{
    value:'哈哈',
    writable:true,
    enumerable:true,
    configurable:true
    });

    const obj = Object.assign({},obj1,obj2);
    console.log(obj); // {type1: 'obj1', type2: 'obj2', value2: '哈哈', Symbol(s1): 's1Symbol', Symbol(s2): 's2Symbol'}
  • Object.assign()中的目标对象为null或者undefined会报错: Object.assign() 中的目标对象不可以是 null 或者undefined

    const s1Symbol = Symbol('s1');
    const s2Symbol = Symbol('s2');
    const obj1 = {
    type1:'obj1',
    [s1Symbol]:'s1Symbol'
    }
    Object.defineProperty(obj1,'value1',{
    value:'哈哈',
    writable:true,
    enumerable:false,
    configurable:true
    });
    const obj2 = {
    type2:'obj2',
    [s2Symbol]:'s2Symbol'
    }
    Object.defineProperty(obj2,'value2',{
    value:'哈哈',
    writable:true,
    enumerable:true,
    configurable:true
    });

    const obj = Object.assign(null,obj1,obj2);
    console.log(obj); // Cannot convert undefined or null to object

原理(Polyfill)

这个polyfill不支持symbol属性, 由于 ES5 中本来就不存在 symbols :

Object.assign = function(target){
if(target === null || target === undefined){
throw new TypeError('Cannot convert undefined or null to object');
}
var object = Object(target);
for(var index=1; index < arguments.length ; index++){
var nextSource = arguments[index];
if(nextSource !== null && nextSource !== undefined){
for(var nextKey in nextSource){
if(Object.prototype.hasOwnProperty.call(nextSource,nextKey)){
object[nextKey] = nextSource[nextKey];
}
}
}
}
return object;
}
const obj1 = {
type1:'obj1',
}
Object.defineProperty(obj1,'value1',{
value:'哈哈',
writable:true,
enumerable:false,
configurable:true
});
const obj2 = {
type2:'obj2',
}
Object.defineProperty(obj2,'value2',{
value:'哈哈',
writable:true,
enumerable:true,
configurable:true
});

const obj = Object.assign({},obj1,obj2);
console.log(obj); // {type1: 'obj1', type2: 'obj2', value2: '哈哈'}

Object.create()


Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的proto

语法

Object.create(proto,[propertiesObject])
  • proto: 新创建对象的原型对象。
  • propertiesObject: 可选。需要传入一个对象,该对象的属性类型参照Object.defineProperties()的第二个参数。如果该参数被指定且不为 undefined,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。Object.create() 的第二个参数与Object.defineProperties() 的第二个参数一样:每个新增属性都通过各自的描述符来描述。以这种方式添加的属性会遮蔽原型对象上的同名属性。

返回值

一个新对象,带着指定的原型对象和属性。

应用场景

  • 通过Object.create()创建对象

    const prototype = {
    type:'prototype'
    }
    const obj = Object.create(prototype,{
    name:{
    value:'obj',
    writable:true,
    enumerable:true,
    configurable:true
    },
    type:{
    value:'obj对象',
    writable:true,
    enumerable:true,
    configurable:true
    }
    });
    console.log(obj); // {name: 'obj', type: 'obj对象' [[Prototype]]: {type: "prototype"}}
  • 实现原型式继承

    const person = {
    name: "一个人",
    friends: ["小明", "小红"],
    };
    const anotherPerson1 = Object.create(person, {
    name: {
    value: "另一个人",
    writable: true,
    enurmable: true,
    configurable: true,
    },
    friends: {
    value: ["另一个人的小明", "另一个人的小红"],
    writable: true,
    enurmable: true,
    configurable: true,
    },
    });
    console.log(anotherPerson1);
    // F {}
    // [[Prototype]]: Object
    // friends: (2)['小明', '小红']
    // name: "一个人"
    // [[Prototype]]: Object
    const anotherPerson2 = Object.create(person, {
    name: {
    value: "另一个人",
    writable: true,
    enurmable: true,
    configurable: true,
    },
    friends: {
    value: ["另一个人的小明", "另一个人的小红"],
    writable: true,
    enurmable: true,
    configurable: true,
    },
    });
    console.log(anotherPerson2);

原理(Polyfill)

Object.create = function (obj, descriptorMap) {
function converToDescriptor(descriptor) {
function hasProperty(obj, property) {
return Object.prototype.hasOwnProperty.call(obj, property);
}
var descriptorNew = {};
if (hasProperty(descriptor, "value")) {
descriptorNew.value = descriptor.value;
}
if (hasProperty(descriptor, "writable")) {
descriptorNew.writable = !!descriptor.writable;
}
if (hasProperty(descriptor, "enurmable")) {
descriptorNew.enumerable = !!descriptor.enumerable;
}
if (hasProperty(descriptor, "configurable")) {
descriptorNew.configurable = !!descriptor.configurable;
}
if (hasProperty(descriptor, "get")) {
var g = descriptor.get;
if (typeof g !== "function" && g != null) {
throw new TypeError("bad get");
}
descriptorNew.get = g;
}
if (hasProperty(descriptor, "set")) {
var s = descriptor.set;
if (typeof s !== "function" && s != null) {
throw new TypeError("bad set");
}
descriptorNew.set = s;
}
if (
("get" in descriptorNew || "set" in descriptorNew) &&
("value" in descriptorNew || "writable" in descriptorNew)
) {
throw new TypeError("identify-confused descriptor");
}
return descriptorNew;
}
if (typeof obj !== "object" && typeof obj !== "function") {
throw new TypeError(
"Object.create support only object as the first argument"
);
} else if (obj == null) {
throw new TypeError(
"Object.create support only object as the first argument"
);
}
if (typeof descriptorMap !== "object" && descriptorMap != null) {
throw new TypeError(
"Object.create support only object as the second argument"
);
}
function F() {}
F.prototype = obj;
var objNew = new F();
var keyArray = Object.keys(descriptorMap);
var descriptorArray = [];
for (var i = 0; i < keyArray.length; i++) {
descriptorArray.push([
keyArray[i],
converToDescriptor(descriptorMap[keyArray[i]]),
]);
}
for (var i = 0; i < descriptorArray.length; i++) {
Object.defineProperty(
objNew,
descriptorArray[i][0],
descriptorArray[i][1]
);
}
return objNew;
};
const obj = Object.create({},{
name:{
value:'柏拉图',
writable:true,
enurmable:true,
configurable:true
},
age:{
value:23,
writable:true,
enumerable:true,
configurable:true
}
});
console.log(obj);

Object.defineProperties()


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

语法

Object.defineProperties(obj, props)
  • obj: 在其上定义或修改属性的对象。
  • props: 要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有两种:数据描述符访问器描述符(更多详情,请参阅Object.defineProperty())。

返回值

应用场景

  • 创建、修改、删除属性

    • 通过数据描述符创建、修改、删除属性

      const obj = {};
      Object.defineProperties(obj,{
      name:{
      value:'柏拉图',
      writable:true,
      enumerable:true,
      configurable:true
      },
      age:{
      value:23,
      writable:true,
      enumerable:true,
      configurable:true
      }
      });

      console.log(obj.name);
      console.log(obj.age);
      obj.name = '柏拉图修改';
      obj.age = '23修改';
      console.log(obj.name);
      console.log(obj.age);
      for(let key in obj){
      console.log(key);
      }
      delete obj.name;
      delete obj.age;
      console.log(obj);
    • 通过存取描述符创建、修改、删除属性

      const obj = {};
      Object.defineProperties(obj,{
      name:{
      enumerable:true,
      configurable:true,
      get(){
      console.log('访问操作');
      return this._name;
      },
      set(newValue){
      console.log('设置操作');
      this._name = newValue;
      }
      },
      age:{
      enumerable:true,
      configurable:true,
      get(){
      console.log('访问操作');
      return this._age;
      },
      set(newValue){
      console.log('设置操作');
      this._age = newValue;
      }
      }
      });

      console.log(obj.name);
      console.log(obj.age);
      obj.name = '柏拉图修改';
      obj.age = '23修改';
      console.log(obj.name);
      console.log(obj.age);
      for(let key in obj){
      console.log(key);
      }
      delete obj.name;
      delete obj.age;
      console.log(obj);

原理(Polyfill)

Object.defineProperties = function (obj, properties) {
function converToDescriptor(desc) {
function hasProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
if (typeof desc !== "object" || desc === null) {
throw new TypeError("bad desc");
}
var descriptor = {};
if (hasProperty(desc, "enumerable")) {
descriptor.enumerable = !!desc.enumerable;
}
if (hasProperty(desc, "configurable")) {
descriptor.configurable = !!desc.configurable;
}
if(hasProperty(desc,'value')){
descriptor.value = desc.value;
}
if(hasProperty(desc,'writable')){
descriptor.writable = !!desc.writable;
}
if(hasProperty(desc,'get')){
var g = desc.get;
if(!typeof g === "function" && typeof g !== 'undefined'){
throw new TypeError('bad get');
}
descriptor.get = g;
}
if(hasProperty(desc,'set')){
var s = desc.set;
if(!typeof s === "function" && typeof s !== "undefined"){
throw new TypeError("bad set");
}
descriptor.set = s;
}
if(('get' in descriptor || 'set' in descriptor) && ('value' in descriptor || 'writable' in descriptor)){
throw new TypeError('identity-confused descriptor');
}
return descriptor;
}
if(typeof obj !== 'object' || obj === null){
throw new TypeError('bad obj');
}
var propertiesObj = Object(properties);
var keyArray = Object.keys(propertiesObj);
var descriptorArray = [];
for(var i=0;i<keyArray.length;i++){
console.log(converToDesCriptor(propertiesObj[keyArray[i]]));
descriptorArray.push([keyArray[i],converToDesCriptor(propertiesObj[keyArray[i]])]);
}
for(var i=0;i<descriptorArray.length;i++){
Object.defineProperty(obj,descriptorArray[i][0],descriptorArray[i][1]);
}
console.log(obj);
return obj;
};
const obj = {};
Object.defineProperties(obj, {
name: {
value: "柏拉图",
writable: true,
enumerable: true,
configurable: true,
},
age: {
value: 23,
writable: true,
enumerable: true,
configurable: true,
},
});
console.log(obj);

Object.entries()


Object.entries() 方法返回一个给定对象自身****可枚举属性的键值对数组,

语法

Object.entries(obj)
  • obj: 可以返回其可枚举属性的键值对的对象。

返回值

给定对象自身可枚举属性的键值对数组。

应用场景

经典问题

  • 如何遍历对象属性?有几种方法以及各自的特点?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      console.log(key); // 输出 name nameProto ageProto
      }
    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']
    • 通过Object.entries(obj) 遍历属性,获取的是对象自身可枚举属性键值对数组

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.entries(obj);
      console.log(result); /// [0: (2) ['name', '柏拉图']]
  • 如何获取对象自身所有可枚举属性?有几种方法?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性,然后通过obj.hasOwnProperty(prop) 进行过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      if(obj.hasOwnProperty(key)){
      console.log(key); // 输出 name
      }
      }
  • 如何获取对象自身所有不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。然后通过Object.keys(obj)过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const allSelfEnumerable = Object.keys(obj);
      const result = Object.getOwnPropertyNames(obj).filter(key=>{
      if(!allSelfEnumerable.includes(key)){
      return true;
      }
      return false;
      });
      console.log(result); // ['age']
  • 如何获取对象自身所有可枚举和不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']

原理(Polyfill)

Object.entries = function(obj){
var keyArray = Object.keys(obj);
var length = keyArray.length;
var result = new Array(length);
var index = 0;
while(index < length){
result[index] = [keyArray[index],obj[keyArray[index]]];
index++;
}
return result;
}
const obj = {
type:'对象',
data:[]
}
console.log(Object.entries(obj));

Object.freeze()


Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。

语法

Object.freeze(obj)
  • obj: 要被冻结的对象。

返回值

被冻结的对象。

应用场景

  • 冻结对象

    const obj = {
    name: "柏拉图",
    age: 23,
    };

    Object.freeze(obj);

    obj.like = '编程'; // 已冻结对象不可添加新属性,添加失效
    obj.name = '柏拉图修改'; // 已冻结对象不可修改属性,修改失效
    delete obj.name; // 已冻结对象不可删除属性,删除失效
    console.log(obj);
  • 冻结数组

    const array = ['哈哈','呵呵'];
    Object.freeze(array);
    array[0] = '哈哈修改';
    console.log(array[0]); // 哈哈

经典问题

  • 如何使对象变得不可扩展?有几种方法可以实现

    • 通过Object.seal(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.seal(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过 Object.freeze()变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.freeze(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过Object.preventExtensions(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.preventExtensions(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}

原理(Polyfill)

Object.fromEntries()


**Object.fromEntries()**方法把键值对列表转换为一个对象。

语法

Object.fromEntries(iterable);
  • iterable: 类似 Array 、 Map 或者其它实现了可迭代协议的可迭代对象。

返回值

一个由该迭代对象条目提供对应属性的新对象。

应用场景

  • Map转化为Object

    const map = new Map([['name','柏拉图'],['age',23]]);
    console.log(map); // Map(2) {'name' => '柏拉图', 'age' => 23}
    const mapObj = Object.fromEntries(map);
    console.log(mapObj); // {name: '柏拉图', age: 23}
  • Array转化为Object

    const array = [
    ["name", "柏拉图"],
    ["age", 23],
    ];
    console.log(array); // (2) [Array(2), Array(2)]
    const arrayObj = Object.fromEntries(array);
    console.log(arrayObj); // {name: '柏拉图', age: 23}
  • 查询字符串转化为Object

    const urlString = 'id=44444&timestamp=43432432432'
    const urlParams = new URLSearchParams(urlString);
    const urlParamsObj = Object.fromEntries(urlParams);
    console.log(urlParamsObj); // {id: '44444', timestamp: '43432432432'}

原理(Polyfill)

Object.getOwnPropertyDescriptor()


Object.getOwnPropertyDescriptor() 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)

语法

Object.getOwnPropertyDescriptor(obj, prop)
  • obj: 需要查找的目标对象
  • prop: 目标对象内属性名称

返回值

如果指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),否则返回 undefined。

应用场景

  • 获取对象属性描述符

    const obj = {};
    Object.defineProperties(obj,{
    name:{
    enumerable:true,
    configurable:true,
    get(){
    console.log('访问操作');
    return this._name;
    },
    set(newValue){
    console.log('设置操作');
    this._name = newValue;
    }
    },
    age:{
    enumerable:true,
    configurable:true,
    get(){
    console.log('访问操作');
    return this._age;
    },
    set(newValue){
    console.log('设置操作');
    this._age = newValue;
    }
    }
    });

    const nameDescriptor = Object.getOwnPropertyDescriptor(obj,'name');
    const ageDescriptor = Object.getOwnPropertyDescriptor(obj,'age');
    console.log(nameDescriptor); // {enumerable: true, configurable: true, get: ƒ, set: ƒ}
    console.log(ageDescriptor); // {enumerable: true, configurable: true, get: ƒ, set: ƒ}

原理(Polyfill)

Object.getOwnPropertyDescriptors()


Object.getOwnPropertyDescriptors() 方法用来获取一个对象的所有自身属性的描述符。

语法

Object.getOwnPropertyDescriptors(obj)
  • obj: 任意对象

返回值

所指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。

应用场景

  • 获取对象自身所有描述符

    const obj = {};
    Object.defineProperties(obj,{
    name:{
    enumerable:true,
    configurable:true,
    get(){
    console.log('访问操作');
    return this._name;
    },
    set(newValue){
    console.log('设置操作');
    this._name = newValue;
    }
    },
    age:{
    enumerable:true,
    configurable:true,
    get(){
    console.log('访问操作');
    return this._age;
    },
    set(newValue){
    console.log('设置操作');
    this._age = newValue;
    }
    }
    });

    const descriptors = Object.getOwnPropertyDescriptors(obj);
    console.log(descriptors);
    // 结果为:
    // {name: {…}, age: {…}}
    // age: {enumerable: true, configurable: true, get: ƒ, set: ƒ}
    // name: {enumerable: true, configurable: true, get: ƒ, set: ƒ}
    // [[Prototype]]: Objects

原理(Polyfill)

Object.getOwnPropertyNames()


Object.getOwnPropertyNames() 方法返回对象自身****可枚举不可枚举属性(但不包括Symbol值作为名称的属性)。

语法

Object.getOwnPropertyNames(obj)
  • obj: 一个对象,其自身的可枚举和不可枚举属性的名称被返回。

返回值

在给定对象上找到的自身属性对应的字符串数组。

应用场景

  • 获取对象自身可枚举不可枚举的属性

    const obj = {};
    Object.defineProperty(obj,'name',{
    value:'柏拉图',
    writable:true,
    enumerable:true, // 属性可枚举
    configurable:true
    });
    Object.defineProperty(obj,'age',{
    value:'柏拉图',
    writable:true,
    enumerable:false, // 属性不可枚举
    configurable:true
    });
    obj.__proto__ = {
    nameProto:'柏拉图',
    ageProto:23
    }

    const result = Object.getOwnPropertyNames(obj);
    console.log(result); //  ['name', 'age']
  • 获取对象自身可枚举属性

    const obj = {};
    Object.defineProperty(obj,'name',{
    value:'柏拉图',
    writable:true,
    enumerable:true, // 属性可枚举
    configurable:true
    });
    Object.defineProperty(obj,'age',{
    value:'柏拉图',
    writable:true,
    enumerable:false, // 属性不可枚举
    configurable:true
    });
    obj.__proto__ = {
    nameProto:'柏拉图',
    ageProto:23
    }

    const allEnumerable = Object.keys(obj);
    const result = Object.getOwnPropertyNames(obj).filter(key=>{
    if(allEnumerable.includes(key)){
    return true
    }
    return false;
    });
    console.log(result); // ['name']
  • 获取对象自身不可枚举的属性

    const obj = {};
    Object.defineProperty(obj,'name',{
    value:'柏拉图',
    writable:true,
    enumerable:true, // 属性可枚举
    configurable:true
    });
    Object.defineProperty(obj,'age',{
    value:'柏拉图',
    writable:true,
    enumerable:false, // 属性不可枚举
    configurable:true
    });
    obj.__proto__ = {
    nameProto:'柏拉图',
    ageProto:23
    }

    const allEnumerable = Object.keys(obj);
    const result = Object.getOwnPropertyNames(obj).filter(key=>{
    if(!allEnumerable.includes(key)){
    return true
    }
    return false;
    });
    console.log(result); // ['age']

经典问题

  • 如何遍历对象属性?有几种方法以及各自的特点?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      console.log(key); // 输出 name nameProto ageProto
      }
    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']
    • 通过Object.entries(obj) 遍历属性,获取的是对象自身可枚举属性键值对数组

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.entries(obj);
      console.log(result); /// [0: (2) ['name', '柏拉图']]
  • 如何获取对象自身所有可枚举属性?有几种方法?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性,然后通过obj.hasOwnProperty(prop) 进行过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      if(obj.hasOwnProperty(key)){
      console.log(key); // 输出 name
      }
      }
  • 如何获取对象自身所有不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。然后通过Object.keys(obj)过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const allSelfEnumerable = Object.keys(obj);
      const result = Object.getOwnPropertyNames(obj).filter(key=>{
      if(!allSelfEnumerable.includes(key)){
      return true;
      }
      return false;
      });
      console.log(result); // ['age']
  • 如何获取对象自身所有可枚举和不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']

原理(Polyfill)

Object.getOwnPropertySymbols()


语法

返回值

应用场景

原理(Polyfill)

Object.getPrototypeOf()


Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)。

语法

Object.getPrototypeOf(object)
  • obj: 要返回其原型的对象。

返回值

给定对象的原型。如果没有继承属性,则返回 null 。

应用场景

  • 获取对象原型

    var proto = {};
    var obj = Object.create(proto);
    Object.getPrototypeOf(obj) === proto; // true

原理(Polyfill)

Object.prototype.hasOwnProperty()


hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(包括可枚举属性和不可枚举属性)。

语法

obj.hasOwnProperty(prop)
  • prop: 要检测的属性的 String 字符串形式表示的名称,或者 Symbol。

返回值

用来判断某个对象是否含有指定的属性的布尔值 Boolean。

应用场景

  • 检测对象自身是否具有属性

    const obj = {};
    Object.defineProperty(obj,'name',{
    value:'柏拉图',
    writable:true,
    enumerable:true, // 属性可枚举
    configurable:true
    });
    Object.defineProperty(obj,'age',{
    value:'柏拉图',
    writable:true,
    enumerable:false, // 属性不可枚举
    configurable:true
    });
    obj.__proto__ = {
    nameProto:'柏拉图',
    ageProto:23
    }
    console.log(obj.hasOwnProperty('name'));
    console.log(obj.hasOwnProperty('age'));
  • 遍历对象自身所有可枚举属性

    const obj = {};
    Object.defineProperty(obj,'name',{
    value:'柏拉图',
    writable:true,
    enumerable:true, // 属性可枚举
    configurable:true
    });
    Object.defineProperty(obj,'age',{
    value:'柏拉图',
    writable:true,
    enumerable:false, // 属性不可枚举
    configurable:true
    });
    obj.__proto__ = {
    nameProto:'柏拉图',
    ageProto:23
    }
    for(let key in obj){
    if(obj.hasOwnProperty(key)){
    console.log(key); // 输出 name
    }
    }

经典问题

  • 如何遍历对象属性?有几种方法以及各自的特点?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      console.log(key); // 输出 name nameProto ageProto
      }
    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']
    • 通过Object.entries(obj) 遍历属性,获取的是对象自身可枚举属性键值对数组

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.entries(obj);
      console.log(result); /// [0: (2) ['name', '柏拉图']]
  • 如何获取对象自身所有可枚举属性?有几种方法?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性,然后通过obj.hasOwnProperty(prop) 进行过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      if(obj.hasOwnProperty(key)){
      console.log(key); // 输出 name
      }
      }
  • 如何获取对象自身所有不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。然后通过Object.keys(obj)过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const allSelfEnumerable = Object.keys(obj);
      const result = Object.getOwnPropertyNames(obj).filter(key=>{
      if(!allSelfEnumerable.includes(key)){
      return true;
      }
      return false;
      });
      console.log(result); // ['age']
  • 如何获取对象自身所有可枚举和不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']

原理(Polyfill)

Object.isExtensible()


Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。

语法

Object.isExtensible(obj)
  • obj: 需要检测的对象

返回值

表示给定对象是否可扩展的一个Boolean 。

应用场景

  • 检测对象是否可扩展,如果之前可扩展,之后变得不可扩展

    • 通过Object.seal(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.seal(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过 Object.freeze()变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.freeze(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过Object.preventExtensions(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.preventExtensions(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}

原理(Polyfill)

Object.isFrozen()


**Object.isFrozen()**方法判断一个对象是否被冻结。

语法

Object.isFrozen(obj)
  • obj: 被检测的对象。

返回值

表示给定对象是否被冻结的Boolean。

应用场景

  • 检测对象是否冻结,如果未冻结,将对象冻结

    const obj = {
    name: "柏拉图",
    age: 23,
    };

    if (!Object.isFrozen(obj)) {
    Object.freeze(obj);
    }

    obj.like = "编程"; // 已冻结对象不可添加新属性,添加失效
    obj.name = "柏拉图修改"; // 已冻结对象不可修改属性,修改失效
    delete obj.name; // 已冻结对象不可删除属性,删除失效
    console.log(obj);

原理(Polyfill)

Object.prototype.isPrototypeOf()


isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。

注意
  1. isPrototypeOf()instanceof 有什么区别?
  • a.isPrototypeOf(b): 针对 a 本身进行检查

  • b instanceof b: 针对 b.prototype 进行检查

语法

prototypeObj.isPrototypeOf(object)
  • object: 在该对象的原型链上搜寻

返回值

Boolean,表示调用对象是否在另一个对象的原型链上。

应用场景

原理(Polyfill)

Object.isSealed()


Object.isSealed() 方法判断一个对象是否被密封。

语法

Object.isSealed(obj)
  • obj: 要被检查的对象。

返回值

表示给定对象是否被密封的一个Boolean 。

应用场景

  • 检测对象是否密封,如果未密封,将对象密封

    const obj = {
    name: "柏拉图",
    age: 23,
    };

    if (Object.isSealed(obj)) {
    Object.seal(obj);
    }
    obj.like = "编程"; // 已密封对象不可添加新属性,添加失效
    obj.name = "柏拉图修改"; // 已密封对象可修改属性,修改成功
    delete obj.name; // 已密封对象不可删除属性,删除失效
    console.log(obj);

    Object.defineProperty(obj, "name", {
    // 尝试为密封对象的属性重新配置描述符,失败
    value: "柏拉图精确管理属性",
    writable: true,
    enumerable: true,
    configurable: true,
    });

    console.log(obj);

原理(Polyfill)

Object.keys()


Object.keys() 方法会返回一个由一个给定对象的自身****可枚举属性组成的数组。

语法

Object.keys(obj)
  • obj: 要返回其枚举自身属性的对象。

返回值

一个表示给定对象自身的所有可枚举属性的字符串数组。

应用场景

  • 获取对象自身所有可枚举属性

    const obj = {};
    Object.defineProperty(obj,'name',{
    value:'柏拉图',
    writable:true,
    enumerable:true, // 属性可枚举
    configurable:true
    });
    Object.defineProperty(obj,'age',{
    value:'柏拉图',
    writable:true,
    enumerable:false, // 属性不可枚举
    configurable:true
    });
    obj.__proto__ = {
    nameProto:'柏拉图',
    ageProto:23
    }
    console.log(Object.keys(obj)); // ['name']

经典问题

  • 如何遍历对象属性?有几种方法以及各自的特点?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      console.log(key); // 输出 name nameProto ageProto
      }
    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']
    • 通过Object.entries(obj) 遍历属性,获取的是对象自身可枚举属性键值对数组

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.entries(obj);
      console.log(result); /// [0: (2) ['name', '柏拉图']]
  • 如何获取对象自身所有可枚举属性?有几种方法?

    • 通过Object.keys(obj) 遍历对象属性,获取的是对象自身的所有可枚举属性

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      console.log(Object.keys(obj)); // ['name']
    • 通过for……in遍历对象属性,获取的是对象自身以及对象原型上的所有可枚举属性,然后通过obj.hasOwnProperty(prop) 进行过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }
      for(let key in obj){
      if(obj.hasOwnProperty(key)){
      console.log(key); // 输出 name
      }
      }
  • 如何获取对象自身所有不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。然后通过Object.keys(obj)过滤

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const allSelfEnumerable = Object.keys(obj);
      const result = Object.getOwnPropertyNames(obj).filter(key=>{
      if(!allSelfEnumerable.includes(key)){
      return true;
      }
      return false;
      });
      console.log(result); // ['age']
  • 如何获取对象自身所有可枚举和不可枚举属性?有几种方法?

    • 通过Object.getOwnPropertyNames(obj)遍历,获取的是对象自身所有可枚举和不可枚举属性。

      const obj = {};
      Object.defineProperty(obj,'name',{
      value:'柏拉图',
      writable:true,
      enumerable:true, // 属性可枚举
      configurable:true
      });
      Object.defineProperty(obj,'age',{
      value:'柏拉图',
      writable:true,
      enumerable:false, // 属性不可枚举
      configurable:true
      });
      obj.__proto__ = {
      nameProto:'柏拉图',
      ageProto:23
      }

      const result = Object.getOwnPropertyNames(obj);
      console.log(result); ['name', 'age']

原理(Polyfill)

Object.preventExtensions()


**Object.preventExtensions()**方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。

语法

Object.preventExtensions(obj)
  • obj: 将要变得不可扩展的对象。

返回值

已经不可扩展的对象。

应用场景

  • 将对象变为不可扩展的对象

    const obj = {
    name:'柏拉图',
    age:23
    }

    Object.preventExtensions(obj);
    obj.like = '编程';
    console.log(obj); // {name: '柏拉图', age: 23}

经典问题

  • 如何使对象变得不可扩展?有几种方法可以实现

    • 通过Object.seal(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.seal(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过 Object.freeze()变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.freeze(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过Object.preventExtensions(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.preventExtensions(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}

原理(Polyfill)

Object.prototype.propertyIsEnumerable()


语法

返回值

应用场景

原理(Polyfill)

Object.seal()


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

语法

Object.seal(obj)
  • ojb: 将要被密封的对象。

返回值

被密封的对象。

应用场景

  • 密封对象

    const obj = {
    name: "柏拉图",
    age: 23,
    };

    Object.seal(obj);
    obj.like = "编程"; // 已密封对象不可添加新属性,添加失效
    obj.name = "柏拉图修改"; // 已密封对象可修改属性,修改成功
    delete obj.name; // 已密封对象不可删除属性,删除失效
    console.log(obj);

    Object.defineProperty(obj,'name',{ // 尝试为密封对象的属性重新配置描述符,失败
    value:'柏拉图精确管理属性',
    writable:true,
    enumerable:true,
    configurable:true
    })

    console.log(obj);

经典问题

  • 如何使对象变得不可扩展?有几种方法可以实现

    • 通过Object.seal(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.seal(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过 Object.freeze()变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.freeze(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}
    • 通过Object.preventExtensions(obj)变得不可扩展

      const obj = {
      name: "柏拉图",
      age: 23,
      };
      if (Object.isExtensible(obj)) {
      Object.preventExtensions(obj);
      }

      obj.like = "编程";
      console.log(obj); // {name: '柏拉图', age: 23}

原理(Polyfill)

Object.setPrototypeOf()


语法

返回值

应用场景

原理(Polyfill)

Object.prototype.toLocaleString()


语法

返回值

应用场景

原理(Polyfill)

Object.prototype.toString()


toString() 方法返回一个表示该对象的字符串。该方法旨在重写(自定义)派生类对象的类型转换的逻辑。

语法

console.log({}.toString()); // [object Object]

console.log({ a:1 }.toString()); // [object Object]

返回值

一个表示该对象的字符串, 返回的字符串内容如下:

[object Object]

应用场景

  • 场景一、各个数据类型重写或覆盖Object.prototype.toString()

  • 场景二、各个数据类型返回各自的Symbol.toStringTag或者标签

    • 原理: Object.prototype.toString() 返回 "[object Type]",这里的 Type 是对象的类型。如果对象有 Symbol.toStringTag 属性,其值是一个字符串,则它的值将被用作 Type。许多内置的对象,包括 MapSymbol,都有 Symbol.toStringTag。一些早于 ES6 的对象没有 Symbol.toStringTag,但仍然有一个特殊的标签。它们包括(标签与下面给出的类型名相同):

      • Array
      • Function
      • Error
      • Boolean
      • Number
      • String
      • Date
      • RegExp
    • 注意: 如果对象有Symbol.toStringTag属性,对象可以通过定义 Symbol.toStringTag 属性来更改 Object.prototype.toString() 的行为,从而导致意想不到的结果

    • 尝试:

      • 返回NumberSymbol.toStringTag或者特殊标签

        const value = 1;
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object Number]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); // Number

        value[Symbol.toStringTag] = "NumberEdit"; // Number 没有 Symbol.toStringTag,但是有一个特殊的标签 “Number” , 所以不会发生重写 Symbol.toStringTag 的情况
        console.log(Object.prototype.toString.call(value)) // [object Number]
      • 返回StringSymbol.toStringTag或者特殊标签

        const value = "哈哈";
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object String]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); // String

        value[Symbol.toStringTag] = "NumberEdit"; // String 没有 Symbol.toStringTag,但是有一个特殊的标签 “String”, 所以不会发生重写 Symbol.toStringTag 的情况
        console.log(Object.prototype.toString.call(value)) // [object String]
      • 返回BooleanSymbol.toStringTag或者特殊标签

        const value = true;
        const reg = /^\[object\s(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object Boolean]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); // Boolean

        value[Symbol.toStringTag] = "NumberEdit"; // Boolean 没有 Symbol.toStringTag,但是有一个特殊的标签 “Boolean”, 所以不会发生重写 Symbol.toStringTag 的情况
        console.log(Object.prototype.toString.call(value)) // [object Boolean]
      • 返回undefinedSymbol.toStringTag或者特殊标签

        const value = undefined;
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object Undefined]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); // Undefined
      • 返回nullSymbol.toStringTag

        const value = null;
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object Null]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); // Null
      • 返回objectSymbol.toStringTag 或者特殊标签

        const value = {};
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object Object]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); //Object

        value[Symbol.toStringTag] = "NumberEdit"; // Object 有 Symbol.toStringTag, 所以会发生重写 Symbol.toStringTag 的情况
        console.log(Object.prototype.toString.call(value)) // [object NumberEdit]
      • 返回ArraySymbol.toStringTag

        const value = [];
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object Array]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); //Array

        value[Symbol.toStringTag] = "NumberEdit"; // Array 有 Symbol.toStringTag, 所以会发生重写 Symbol.toStringTag 的情况
        console.log(Object.prototype.toString.call(value)) // [object NumberEdit]
      • 返回DateSymbol.toStringTag

        const value = new Date();
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object Date]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); //Date

        value[Symbol.toStringTag] = "NumberEdit"; // Date 有 Symbol.toStringTag
        console.log(Object.prototype.toString.call(value)) // [object NumberEdit]
      • 返回RegExpSymbol.toStringTag

        const value = /a/;
        const reg = /^\[object\s+(.*)\]$/;
        console.log(Object.prototype.toString.call(value)) // [object RegExp]
        const type = reg.exec(Object.prototype.toString.call(value))?.[1];
        console.log(type); //RegExp

        value[Symbol.toStringTag] = "NumberEdit"; // RegExp 有 Symbol.toStringTag
        console.log(Object.prototype.toString.call(value)) // [object NumberEdit]
  • 场景三、自定义对象如何获得[object MyObject]类型

    解决方案: 更改原型上的[Symbol.toStringTag]属性即可

    function Person(){

    }
    Person.prototype[Symbol.toStringTag] = "Person";
    const person = new Person();

    console.log(Object.prototype.toString.call(person));
  • 场景四、Object.prototype.toString.call(Boolean.prototype) 结果是什么?

原理(Polyfill)

Object.prototype.valueOf()


ObjectvalueOf() 方法将 this 值转换为一个对象。此方法旨在用于自定义类型转换的逻辑时,重写派生类对象。

语法

object.valueOf()

返回值

返回 this 值本身,如果尚未转换为对象,则转换为对象。因此它的返回值将从不会被任何原始值转换算法使用。

const obj = { foo: 1 };
console.log(obj.valueOf() === obj); // true

应用场景

原理(Polyfill)

Object.values()


语法

返回值

应用场景

原理(Polyfill)