前言

对象(object)是 JavaScript 最重要的数据结构。ES6中的重大升级,更使其如虎添翼,关于数据结构本身的改变,详见《纵深精耕--ES6对JS对象的极大提升》。这次先把JS中的对象方法做一次最详全的展示。

这篇的结构与拙文《拘神遣将--最详全的JS数组方法总结》相仿,在此省略赘述。

开始之前,劣者依旧先将本文谈到的方法(21个)按讲解次序阵列下方,供读者参考:

ES5:Object.create()、Object.defineProperty()、Object.defineProperties()、Object.getPrototypeOf()、Object.getOwnPropertyDescriptor()、Object.keys()、Object.getOwnPropertyNames()、Object.preventExtensions()、Object.isExtensible()、Object.seal()、Object.isSealed()、Object.freeze()、Object.isFrozen()ES6:Object.is()、Object.assign()、Object.getOwnPropertyDescriptors()、Object.setPrototypeOf()、Object.getPrototypeOf()、Object.keys()、Object.values()、Object.entries()、Object.fromEntries()

正文

1、Object.create(obj):方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。

Object.create方法的实质是新建一个空的构造函数F,然后让F.prototype属性指向参数对象obj,最后返回一个F的实例,从而实现让该实例继承obj的属性。
实际上,Object.create也可以用下面的代码代替:

Object.create = function (obj) {function F() {}F.prototype = objreturn new F()}// 或者可以更直观些Object.create = function (obj) {let F = {}F.__proto__=objreturn F
}

Object.create方法生成的新对象,动态继承了原型。在原型上添加或修改任何方法,都会立刻反映在新对象之上,可以将其视作是一种浅拷贝。下面的代码是一个例子:

let obj1 = { p: 1 };
let obj2 = Object.create(obj1);obj1.p = 2;
obj2.p // 2//在obj1上添加的属性,立刻反应到了新的对象obj2上

除了对象原型,Object.create方法还可以接受第二个参数。该参数是一个属性描述对象,它所描述的对象属性,会添加到目标对象,作为目标对象自身的属性。

let obj = Object.create({}, {p1: {value: 123,enumerable: true,configurable: true,writable: true,},p2: {value: 'abc',enumerable: true,configurable: true,writable: true,}
});// 等同于
let obj = Object.create({})
obj.p1 = 123
obj.p2 = 'abc'

如果理解了Object.create,就可以轻松去理解ES6转ES5的继承代码了。

2、Object.defineProperty(obj, prop, descript): 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

本方法接收三个参数,分别如下:
obj:要在其上定义属性的对象。
prop:要定义或修改的属性的名称。
Descriptor:将被定义或修改的属性描述符,返回被传递给函数的对象。

下面的代码是一个例子:

let obj = {};
Object.defineProperty(obj, 'name', {value: '斛律光'
});console.log(obj); // '斛律光'// 成功地给目标对象定义了name属性

使用Object.defineProperty可以实现vue中的双向绑定,详见拙文《浅析Vue的两项原理》。

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

该方法有两个参数:
obj: 在其上定义或修改属性的对象。
props: 要定义其可枚举属性或修改的属性描述符的对象。

在这里稍微提一下对象中存在的属性描述符,主要有两种:数据描述符和访问器描述符,如下:

configurable、enumerable、value、writable、get、set

var obj = {};
Object.defineProperties(obj, {'property1': {value: true,writable: true},'property2': {value: 'Hello',writable: false}// Objectproperty1: trueproperty2: "Hello"__proto__: Object
});

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

该方法只有一个参数obj,表示要返回其原型的对象,返回值是给定对象的原型。

如果没有继承属性,则返回 null。下面的代码是一个例子:

const prototype1 = {};
const object1 = Object.create(prototype1);console.log(Object.getPrototypeOf(object1) === prototype1);
// true// object1是Object.create()以prototype1为蓝本创造的对象,它的原型自然指向prototype1

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

该方法接收两个参数,分别如下:

obj:需要查找的目标对象
prop:目标对象内属性名称

关于其返回值,如果指定的属性存在于对象上,则返回其属性描述符对象,否则返回 undefind。下面的代码是一个例子:

let o, do = { get foo() { return 17 } }d = Object.getOwnPropertyDescriptor(o, "foo")
// d {
//   configurable: true,
//   enumerable: true,
//   get: /*the getter function*/,
//   set: undefined
// }
// 拿到了foo()的自有属性描述对象o = { bar: 66 }d = Object.getOwnPropertyDescriptor(o, "bar")
// d {
//   configurable: true,
//   enumerable: true,
//   value: 66,
//   writable: true
// }
// o = {}Object.defineProperty(o, "baz", {value: 76341,writable: false,enumerable: false
})d = Object.getOwnPropertyDescriptor(o, "baz")
// d {
//   value: 76341,
//   writable: false,
//   enumerable: false,
//   configurable: false
// }/* Object.defineProperty()方法给o定义了baz属性,d通过
Object.getOwnPropertyDescriptor()获得了o的自有属性描述符对象。*/

6、Object.keys(obj):方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组。

参数对象是 被要求返回其自身属性的对象,返回值是一个可表示给定对象所有可枚举属性字符串数组

下面的代码从四个不同的角度去举例:

// 数组
let arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']// 类似数组的对象
let obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']// 随机索引的类数组对象
let anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']// 不可枚举属性:getFoo
let myObj = Object.create({}, {getFoo: {value: function () { return this.foo; }}
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // console: ['foo']

7、Object.getOwnPropertyNames(obj):方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。

该方法的返回值是一个字符串数组。

// 数组
var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]// 类数组对象
var obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]// 使用Array.forEach输出属性名和属性值
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {console.log(val + " -> " + obj[val]);
});
// 输出
// 0 -> a
// 1 -> b
// 2 -> c//不可枚举属性
var my_obj = Object.create({}, {getFoo: {value: function() { return this.foo; },enumerable: false}
});
my_obj.foo = 1;console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]

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

该方法会返回一个已经不可拓展的对象。比较直观,简单。下面代码是一个例子:

// Object.preventExtensions将原对象变的不可扩展,并且返回原对象.
let obj = {};
let obj2 = Object.preventExtensions(obj);
obj === obj2;  // true// 使用Object.defineProperty方法为一个不可扩展的对象添加新属性会抛出异常.
let nonExtensible = { removable: true };
Object.preventExtensions(nonExtensible);
Object.defineProperty(nonExtensible, "new", { value: 8675309 }); // 抛出TypeError异常

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

很简单的方法,返回值是Boolean。

// 新对象默认是可扩展的.
let empty = {};
Object.isExtensible(empty); // === true// ...可以变的不可扩展.
Object.preventExtensions(empty);
Object.isExtensible(empty); // === false

10、Object.seal(obj):方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要可写就可以改变。

参数是将要被密封的对象,返回值是被密封的对象。

Object.seal() 比 Object.isExtensible() 严格的一点是,它将不在允许配置当前所有属性。

let arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]// 类数组对象
let obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]// 使用Array.forEach输出属性名和属性值
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {console.log(val + " -> " + obj[val]);
});
// 输出
// 0 -> a
// 1 -> b
// 2 -> c//不可枚举属性
let my_obj = Object.create({}, {getFoo: {value: function() { return this.foo; },enumerable: false}
});
my_obj.foo = 1;console.log(Object.getOwnPropertyNames(my_obj).sort()); // ["foo", "getFoo"]

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

很简单的方法,返回值是Boolean。

// 新建的对象默认不是密封的.
var empty = {};
Object.isSealed(empty); // === false// 如果你把一个空对象变的不可扩展,则它同时也会变成个密封对象.
Object.preventExtensions(empty);
Object.isSealed(empty); // === true

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

冻结可以视作是对一个对象最严格的限制。

该方法返回传递的对象,而不是创建一个被冻结的副本。下面的例子将展示一些对冻结对象操作的结果:

var obj = {prop: function() {},foo: 'bar'
};// 新的属性会被添加, 已存在的属性可能
// 会被修改或移除
obj.foo = 'baz';
obj.lumpy = 'woof';
delete obj.prop;// 作为参数传递的对象与返回的对象都被冻结
// 所以不必保存返回的对象(因为两个对象全等)
var o = Object.freeze(obj);o === obj; // true
Object.isFrozen(obj); // === true// 现在任何改变都会失效
obj.foo = 'quux'; // 静默地不做任何事
// 静默地不添加此属性
obj.quaxxor = 'the friendly duck';// 在严格模式,如此行为将抛出 TypeErrors
function fail(){'use strict';obj.foo = 'sparky'; // throws a TypeErrordelete obj.quaxxor; // 返回true,因为quaxxor属性从来未被添加obj.sparky = 'arf'; // throws a TypeError
}fail();// 试图通过 Object.defineProperty 更改属性
// 下面两个语句都会抛出 TypeError.
Object.defineProperty(obj, 'ohai', { value: 17 });
Object.defineProperty(obj, 'foo', { value: 'eit' });// 也不能更改原型
// 下面两个语句都会抛出 TypeError.
Object.setPrototypeOf(obj, { x: 20 })
obj.__proto__ = { x: 20 }

13、Object.isFrozen(obj):方法判断一个对象是否被冻结。

很简单的方法,返回值是Boolean。

// 一个对象默认是可扩展的,所以它也是非冻结的.
Object.isFrozen({}); // === false// 一个不可扩展的空对象同时也是一个冻结对象.
let vacuouslyFrozen = Object.preventExtensions({});
Object.isFrozen(vacuouslyFrozen) //=== true;// 一个非空对象默认也是非冻结的.
let oneProp = { p: 42 };
Object.isFrozen(oneProp) //=== false// 让这个对象变的不可扩展,并不意味着这个对象变成了冻结对象,
// 因为p属性仍然是可以配置的(而且可写的).
Object.preventExtensions(oneProp);
Object.isFrozen(oneProp) //=== false

14、Object.is(obj, obj):它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

Object.is()的参数是要比较的两个值,返回值是Boolean。

看下面的代码:

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false// +0不等于-0
+0 === -0 //true
NaN === NaN // false// NaN等于自身
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
​

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

Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象

该方法有不少值得推敲和注意的点,下面的代码举出基本用法,其他部分详见拙文《Object.assign详解》

const target = { a: 1 };const source1 = { b: 2 };
const source2 = { c: 3 };Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}// 如果目标对象与源对象有同名属性,或多个源对象有同名属性
// 则后面的属性会覆盖前面的属性。const target = { a: 1, b: 1 };const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}// source2 中的 c属性覆盖了source1  中的 c属性

16、Object.getOwnPropertyDescriptors():返回指定对象所有自身属性(非继承属性)的描述对象。

ES5的Object.getOwnPropertyDescriptor()方法会返回某个对象属性的描述对象(descriptor)。ES2017引入了

Object.getOwnPropertyDescriptor()方法,返回指定对象所有的自身属性(非继承属性)的描述对象。

const obj = {foo: 123,get bar() { return 'abc' }
};Object.getOwnPropertyDescriptors(obj)
// { foo:
//    { value: 123,
//      writable: true,
//      enumerable: true,
//      configurable: true },
//   bar:
//    { get: [Function: get bar],
//      set: undefined,
//      enumerable: true,
//      configurable: true } }

上面代码中,Object.getOwnPropertyDescriptors()方法返回一个对象,所有原对象的属性名都是该对象的属性名,对应的属性值就是该属性的描述对象。

17、Object.setPrototypeOf():方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。

// 格式
Object.setPrototypeOf(object, prototype)// 用法
const o = Object.setPrototypeOf({}, null);

该方法等同于下面的函数。

function setPrototypeOf(obj, proto) {obj.__proto__ = proto;return obj;
}

下面是一个例子。

let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);proto.y = 20;
proto.z = 40;obj.x // 10
obj.y // 20
obj.z // 40

18、Object.getPrototypeOf():该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。

该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。

Object.getPrototypeOf(obj);

下面是一个例子。

function Rectangle() {// ...
}const rec = new Rectangle();Object.getPrototypeOf(rec) === Rectangle.prototype
// trueObject.setPrototypeOf(rec, Object.prototype);
Object.getPrototypeOf(rec) === Rectangle.prototype

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

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

const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]

返回数组的成员顺序,与本章的《属性的遍历》部分介绍的排列规则一致。

const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]

上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是bca

Object.values只返回对象自身的可遍历属性。

const obj = Object.create({}, {p: {value: 42}});
Object.values(obj) // []

上面代码中,Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的,因为p的属性描述对象的enumerable默认是falseObject.values不会返回这个属性。只要把enumerable改成trueObject.values就会返回属性p的值。

const obj = Object.create({}, {p:{value: 42,enumerable: true}
});
Object.values(obj) // [42]

Object.values会过滤属性名为 Symbol 值的属性。

Object.values({ [Symbol()]: 123, foo: 'abc' });
// ['abc']

如果Object.values方法的参数是一个字符串,会返回各个字符组成的一个数组。

Object.values('foo')
// ['f', 'o', 'o']

上面代码中,字符串会先转成一个类似数组的对象。字符串的每个字符,就是该对象的一个属性。因此,Object.values返回每个属性的键值,就是各个字符组成的一个数组。

如果参数不是对象,Object.values会先将其转为对象。由于数值和布尔值的包装对象,都不会为实例添加非继承的属性。所以,Object.values会返回空数组。

Object.values(42) // []
Object.values(true) // []

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

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

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

除了返回值不一样,该方法的行为与Object.values基本一致。

如果原对象的属性名是一个 Symbol 值,该属性会被忽略。

Object.entries({ [Symbol()]: 123, foo: 'abc' });
// [ [ 'foo', 'abc' ] ]

上面代码中,原对象有两个属性,Object.entries只输出属性名非 Symbol 值的属性。将来可能会有Reflect.ownEntries()方法,返回对象自身的所有属性。

Object.entries的基本用途是遍历对象的属性。

let obj = { one: 1, two: 2 };
for (let [k, v] of Object.entries(obj)) {console.log(`${JSON.stringify(k)}: ${JSON.stringify(v)}`);
}
// "one": 1
// "two": 2

Object.entries方法的另一个用处是,将对象转为真正的Map结构。

const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
map // Map { foo: "bar", baz: 42 }

自己实现Object.entries方法,非常简单。

// Generator函数的版本
function* entries(obj) {for (let key of Object.keys(obj)) {yield [key, obj[key]];}
}// 非Generator函数的版本
function entries(obj) {let arr = [];for (let key of Object.keys(obj)) {arr.push([key, obj[key]]);}return arr;
}

21、Object.fromEntries():方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。

Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。

Object.fromEntries([['foo', 'bar'],['baz', 42]
])
// { foo: "bar", baz: 42 }

该方法的主要目的,是将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象。

// 例一
const entries = new Map([['foo', 'bar'],['baz', 42]
]);Object.fromEntries(entries)
// { foo: "bar", baz: 42 }// 例二
const map = new Map().set('foo', true).set('bar', false);
Object.fromEntries(map)
// { foo: true, bar: false }

该方法的一个用处是配合URLSearchParams对象,将查询字符串转为对象。

Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
// { foo: "bar", baz: "qux" }

荀令衣香--JavaScript全对象方法总结相关推荐

  1. 【JavaScript String对象方法】字符串片段提取:slice()、substring()、substr()

    当参数相同时,返回结果是否相同 slice() substring() substr() 单正参 ✅ ✅ ✅ 单负参 ✅ ❌ (负参转换为 0,返回全字符串) ✅ 双正参 ✅ ✅ ❌ 双负参 ✅ nu ...

  2. JavaScript Array 对象方法

    data.sort(function(a,b){return a.time>b.time?1:-1}); http://www.w3school.com.cn/jsref/jsref_obj_a ...

  3. JavaScript中对象(Object)的方法

    JavaScript中对象方法总结: 资料来源:网道-互联网开发文档 [https://wangdoc.com/] 1.Object.getPrototypeOf(Object) Object.get ...

  4. JavaScript常用事件+方法

    javascript常用事件onclick 单击 ondblclick 双击 onfocus 元素获得焦点 onblur 元素失去焦点 onmouseover 鼠标移到某元素之上 onmouseout ...

  5. JavaScript基础12-day14【DOM查询(获取元素节点、获取元素节点的子节点)、全选练习、DOM增删改、DOM添加删除记录、Window对象方法】

    学习地址: 谷粒学院--尚硅谷 哔哩哔哩网站--尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通) JavaScript基础.高级学习笔记汇总表[尚硅谷最新版Ja ...

  6. JavaScript 复制对象与Object.assign方法无法实现深复制

    在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型.基本数据类型包括Number.Boolean.String.Null.String.Symbol(ES6 新增),而复 ...

  7. javascript Navigator对象属性和方法

    Navigator对象 Navigator 对象包含的属性描述了正在使用的浏览器.可以使用这些属性进行平台专用的配置.虽然这个对象的名称显而易见 的是 Netscape 的 Navigator 的浏览 ...

  8. javascript 数组对象中的迭代方法

    /* javascript 数组对象中的迭代方法 * ECMAScript5为数组定义了5个迭代方法.每个方法都接受两个参数,第一个是进行迭代的函数,第二个是该函数的作用域对象[可选]. * 进行迭代 ...

  9. javascript 对象方法、类方法、原型方法

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

最新文章

  1. 物体的三维识别与6D位姿估计:PPF系列论文介绍(五)
  2. HTML连载14-文字属性补充简写
  3. 云栖大会特享,热营抢先开,阿里云专家的私教课,限时抢报!
  4. linux云服务终端提示符显示-bash-4.2#解决方法
  5. Selenium常用API的使用java语言之13-多表单切换
  6. 设置单元格填充方式_单元格的选择及设置单元格格式
  7. 人工智能python基础知识_AI 人工智能基础知识-习题
  8. 实现一个输入程序,接收从 键盘读入的字符串。当字符串中所含字符个数少于程序设定的上限时,输出这个字符串;否则抛出MyStringException1异常,在异常处理中要求重新输入新的字符串或者中断程序
  9. 系统监视器(Sysmon)工具的使用
  10. w ndows模拟器,DS4Windows模拟器
  11. Latex给表格加脚注
  12. 如何选择和更换阿里云服务器操作系统?
  13. 阿里云对象存储OSS上传照片(附源码)
  14. 神木林服务器未能,《梦幻西游2》2015年9月22日定期维护公告
  15. 笔记_KMeans聚类
  16. linux创建文档并且打字,与 Linux 一起学习:学习打字
  17. 160亿数据点图表控件LightningChart振动分析可以检测什么?
  18. Java打开窗体基础用法
  19. 计算机网络的 89 个核心概念
  20. 视觉和imu(惯性传感器)( 一)

热门文章

  1. 网页上爬取数据(Java版)通俗易懂
  2. 微信小程序数据绑定和事件绑定
  3. 福晰阅读器打开PDF时如何不展开目录
  4. tf.concat, tf.stack和tf.unstack的用法
  5. acme.sh证书申请
  6. 数控G代码编程详解大全
  7. SpringBoot从入门到精通教程(二十七)- @Valid注解用法详解+全局处理器Exception优雅处理参数验证用法
  8. 简练软考知识点整理-项目全面质量管理TQM
  9. ( 转载)改变人类历史的17大数学方程
  10. 快速找到 Linux Kernel 中各种函数原型的方法