JavaScript 对象所有API解析【2024版】

function Vue(){

console.log(‘test vue’);

}

function http(){

console.log(‘我是调用接口的http’);

}

Vue.prototype.$http = http;

var vm = new Vue();

vm.$http()

vm.$http = 1; // 一旦被修改,虽然一般正常情况下不会被修改

vm.$http(); // 再次调用报错

熟悉Object.defineProperty或者说熟悉对象API的人,一般是如下代码写的,则不会出现被修改的问题。

function Vue(){

console.log(‘test vue’);

};

function http(){

console.log(‘我是调用接口的http’);

};

Object.defineProperty(Vue.prototype, ‘$http’, {

get(){

return http;

}

});

var vm = new Vue();

vm.$http();

vm.$http = 1; // 这里无法修改

vm.$http(); // 调用正常

vue-router 源码里就是类似这样写的[1],this.$routerthis.$route无法修改。

// vue-router 源码

Object.defineProperty(Vue.prototype, ‘$router’, {

get () { return this._routerRoot._router }

})

Object.defineProperty(Vue.prototype, ‘$route’, {

get () { return this._routerRoot._route }

})

以下是正文,祝阅读愉快~

之前看到【深度长文】JavaScript 数组所有 API 全解密[2]和JavaScript 字符串所有 API 全解密[3]这两篇高质量的文章。发现没写对象 API 解析(估计是博主觉得简单,就没写)。刚好我看到《JavaScript 面向对象编程指南(第 2 版)》,觉得有必要写(或者说 chao)一下,也好熟悉下对象的所有 API 用法。

创建对象的两种方式:

var o = new Object();

var o = {}; // 推荐

该构造器可以接受任何类型的参数,并且会自动识别参数的类型,并选择更合适的构造器来完成相关操作。比如:

var o = new Object(‘something’);

o.constructor; // ƒ String() { [native code] }

var n = new Object(123);

n.constructor; // ƒ Number() { [native code] }

一、Object 构造器的成员


Object.prototype

该属性是所有对象的原型(包括 Object对象本身),语言中的其他对象正是通过对该属性上添加东西来实现它们之间的继承关系的。所以要小心使用。比如:

var s = new String(‘若川’);

Object.prototype.custom = 1;

console.log(s.custom); // 1

二、Object.prototype 的成员


Object.prototype.constructor

该属性指向用来构造该函数对象的构造器,在这里为Object()

Object.prototype.constructor === Object; // true

var o = new Object();

o.constructor === Object; // true

Object.prototype.toString(radix)

该方法返回的是一个用于描述目标对象的字符串。特别地,当目标是一个 Number 对象时,可以传递一个用于进制数的参数radix,该参数radix,该参数的默认值为 10。

var o = {prop:1};

o.toString(); // ‘[object Object]’

var n = new Number(255);

n.toString(); // ‘255’

n.toString(16); // ‘ff’

Object.prototype.toLocaleString()

该方法的作用与toString()基本相同,只不过它做一些本地化处理。该方法会根据当前对象的不同而被重写,例如Date(),Number(),Array(),它们的值都会以本地化的形式输出。当然,对于包括Object()在内的其他大多数对象来说,该方法与toString()是基本相同的。在浏览器环境下,可以通过BOM对象Navigatorlanguage属性(在IE中则是userLanguage)来了解当前所使用的语言:

navigator.language; //‘en-US’

Object.prototype.valueOf()

该方法返回的是用基本类型所表示的this值,如果它可以用基本类型表示的话。如果Number对象返回的是它的基本数值,而Date对象返回的是一个时间戳(timestamp)。如果无法用基本数据类型表示,该方法会返回this本身。

// Object

var o = {};

typeof o.valueOf(); // ‘object’

o.valueOf() === o; // true

// Number

var n = new Number(101);

typeof n; // ‘object’

typeof n.vauleOf; // ‘function’

typeof n.valueOf(); // ‘number’

n.valueOf() === n; // false

// Date

var d = new Date();

typeof d.valueOf(); // ‘number’

d.valueOf(); // 1503146772355

Object.prototype.hasOwnProperty(prop)

该方法仅在目标属性为对象自身属性时返回true,而当该属性是从原型链中继承而来或根本不存在时,返回false

var o = {prop:1};

o.hasOwnProperty(‘prop’); // true

o.hasOwnProperty(‘toString’); // false

o.hasOwnProperty(‘formString’); // false

Object.prototype.isPrototypeOf(obj)

如果目标对象是当前对象的原型,该方法就会返回true,而且,当前对象所在原型上的所有对象都能通过该测试,并不局限与它的直系关系。

var s = new String(‘’);

Object.prototype.isPrototypeOf(s); // true

String.prototype.isPrototypeOf(s); // true

Array.prototype.isPrototypeOf(s); // false

Object.prototype.propertyIsEnumerable(prop)

如果目标属性能在for in循环中被显示出来,该方法就返回true

var a = [1,2,3];

a.propertyIsEnumerable(‘length’); // false

a.propertyIsEnumerable(0); // true

三、在ES5中附加的Object属性


ES3中,除了一些内置属性(如:Math.PI),对象的所有的属性在任何时候都可以被修改、插入、删除。在ES5中,我们可以设置属性是否可以被改变或是被删除——在这之前,它是内置属性的特权。ES5中引入了属性描述符的概念,我们可以通过它对所定义的属性有更大的控制权。这些属性描述符(特性)包括:

value——当试图获取属性时所返回的值。writable——该属性是否可写。enumerable——该属性在for in循环中是否会被枚举configurable——该属性是否可被删除。set()——该属性的更新操作所调用的函数。get()——获取属性值时所调用的函数。另外,数据描述符(其中属性为:enumerableconfigurablevaluewritable)与存取描述符(其中属性为enumerableconfigurableset()get())之间是有互斥关系的。在定义了set()get()之后,描述符会认为存取操作已被 定义了,其中再定义valuewritable引起错误。以下是_ES3_风格的属性定义方式:

var person = {};

person.legs = 2;

以下是等价的 ES5 通过数据描述符定义属性的方式:

var person = {};

Object.defineProperty(person, ‘legs’, {

value: 2,

writable: true,

configurable: true,

enumerable: true

});

其中, 除了 value 的默认值为undefined以外,其他的默认值都为false。这就意味着,如果想要通过这一方式定义一个可写的属性,必须显示将它们设为true。或者,我们也可以通过ES5的存储描述符来定义:

var person = {};

Object.defineProperty(person, ‘legs’, {

set:function(v) {

return this.value = v;

},

get: function(v) {

return this.value;

},

configurable: true,

enumerable: true

});

person.legs = 2;

这样一来,多了许多可以用来描述属性的代码,如果想要防止别人篡改我们的属性,就必须要用到它们。此外,也不要忘了浏览器向后兼容ES3方面所做的考虑。例如,跟添加Array.prototype属性不一样,我们不能在旧版的浏览器中使用shim这一特性。另外,我们还可以(通过定义nonmalleable属性),在具体行为中运用这些描述符:

var person = {};

Object.defineProperty(person, ‘heads’, {value: 1});

person.heads = 0; // 0

person.heads; // 1 (改不了)

delete person.heads; // false

person.heads // 1 (删不掉)

Object.defineProperty(obj, prop, descriptor) (ES5)

具体用法可参见上文,或者查看 MDN。MDN Object.defineProperty(obj, descriptor)[4]

Vue.js 文档:**如何追踪变化**[5] 把一个普通 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是仅 ES5 支持,且无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。

Object.defineProperties(obj, props) (ES5)

该方法的作用与defineProperty()基本相同,只不过它可以用来一次定义多个属性。比如:

var glass = Object.defineProperties({}, {

‘color’: {

value: ‘transparent’,

writable: true

},

‘fullness’: {

value: ‘half’,

writable: false

}

});

glass.fullness; // ‘half’

Object.getPrototypeOf(obj) (ES5)

之前在ES3中,我们往往需要通过Object.prototype.isPrototypeOf()去猜测某个给定的对象的原型是什么,如今在ES5中,我们可以直接询问改对象“你的原型是什么?”

Object.getPrototypeOf([]) === Array.prototype; // true

Object.getPrototypeOf(Array.prototype) === Object.prototype; // true

Object.getPrototypeOf(Object.prototype) === null; // true

Object.create(obj, descr) (ES5)

该方法主要用于创建一个新对象,并为其设置原型,用(上述)属性描述符来定义对象的原型属性。

var parent = {hi: ‘Hello’};

var o = Object.create(parent, {

prop: {

value: 1

}

});

o.hi; // ‘Hello’

// 获得它的原型

Object.getPrototypeOf(parent) === Object.prototype; // true 说明parent的原型是Object.prototype

Object.getPrototypeOf(o); // {hi: “Hello”} // 说明o的原型是{hi: “Hello”}

o.hasOwnProperty(‘hi’); // false 说明hi是原型上的

o.hasOwnProperty(‘prop’); // true 说明prop是原型上的自身上的属性。

现在,我们甚至可以用它来创建一个完全空白的对象,这样的事情在ES3中可是做不到的。

var o = Object.create(null);

typeof o.toString(); // ‘undefined’

Object.getOwnPropertyDesciptor(obj, property) (ES5)

该方法可以让我们详细查看一个属性的定义。甚至可以通过它一窥那些内置的,之前不可见的隐藏属性。

Object.getOwnPropertyDescriptor(Object.prototype, ‘toString’);

// {writable: true, enumerable: false, configurable: true, value: ƒ toString()}

Object.getOwnPropertyNames(obj) (ES5)

该方法返回一个数组,其中包含了当前对象所有属性的名称(字符串),不论它们是否可枚举。当然,也可以用Object.keys()来单独返回可枚举的属性。

Object.getOwnPropertyNames(Object.prototype);

// [“defineGetter”, “defineSetter”, “hasOwnProperty”, “lookupGetter”, “lookupSetter”, “propertyIsEnumerable”, “toString”, “valueOf”, “proto”, “constructor”, “toLocaleString”, “isPrototypeOf”]

Object.keys(Object.prototype);

// []

Object.getOwnPropertyNames(Object);

// [“length”, “name”, “arguments”, “caller”, “prototype”, “assign”, “getOwnPropertyDescriptor”, “getOwnPropertyDescriptors”, “getOwnPropertyNames”, “getOwnPropertySymbols”, “is”, “preventExtensions”, “seal”, “create”, “defineProperties”, “defineProperty”, “freeze”, “getPrototypeOf”, “setPrototypeOf”, “isExtensible”, “isFrozen”, “isSealed”, “keys”, “entries”, “values”]

Object.keys(Object);

// []

Object.preventExtensions(obj) (ES5)

Object.isExtensible(obj) (ES5)

preventExtensions()方法用于禁止向某一对象添加更多属性,而isExtensible()方法则用于检查某对象是否还可以被添加属性。

var deadline = {};

Object.isExtensible(deadline); // true

deadline.date = ‘yesterday’; // ‘yesterday’

Object.preventExtensions(deadline);

Object.isExtensible(deadline); // false

deadline.date = ‘today’;

deadline.date; // ‘today’

// 尽管向某个不可扩展的对象中添加属性不算是一个错误操作,但它没有任何作用。

deadline.report = true;

deadline.report; // undefined

Object.seal(obj) (ES5)

Object.isSeal(obj) (ES5)

seal()方法可以让一个对象密封,并返回被密封后的对象。seal()方法的作用与preventExtensions()基本相同,但除此之外,它还会将现有属性 设置成不可配置。也就是说,在这种情况下,我们只能变更现有属性的值,但不能删除或(用defineProperty())重新配置这些属性,例如不能将一个可枚举的属性改成不可枚举。

var person = {legs:2};

// person === Object.seal(person); // true

Object.isSealed(person); // true

Object.getOwnPropertyDescriptor(person, ‘legs’);

// {value: 2, writable: true, enumerable: true, configurable: false}

delete person.legs; // false (不可删除,不可配置)

Object.defineProperty(person, ‘legs’,{value:2});

person.legs; // 2

person.legs = 1;

person.legs; // 1 (可写)

Object.defineProperty(person, “legs”, { get: function() { return “legs”; } });

// 抛出TypeError异常

Object.freeze(obj) (ES5)

Object.isFrozen(obj) (ES5)

freeze()方法用于执行一切不受seal()方法限制的属性值变更。Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。

var deadline = Object.freeze({date: ‘yesterday’});

deadline.date = ‘tomorrow’;

deadline.excuse = ‘lame’;

deadline.date; // ‘yesterday’

deadline.excuse; // undefined

Object.isSealed(deadline); // true;

Object.isFrozen(deadline); // true

Object.getOwnPropertyDescriptor(deadline, ‘date’);

// {value: “yesterday”, writable: false, enumerable: true, configurable: false} (不可配置,不可写)

Object.keys(deadline); // [‘date’] (可枚举)

Object.keys(obj) (ES5)

该方法是一种特殊的for-in循环。它只返回当前对象的属性(不像for-in),而且这些属性也必须是可枚举的(这点和Object.getOwnPropertyNames()不同,不论是否可以枚举)。返回值是一个字符串数组。

Object.prototype.customProto = 101;

Object.getOwnPropertyNames(Object.prototype);

// […, “constructor”, “toLocaleString”, “isPrototypeOf”, “customProto”]

Object.keys(Object.prototype); // [‘customProto’]

var o = {own: 202};

o.customProto; // 101

Object.keys(o); // [‘own’]

最后

sterday’

deadline.excuse; // undefined

Object.isSealed(deadline); // true;

Object.isFrozen(deadline); // true

Object.getOwnPropertyDescriptor(deadline, ‘date’);

// {value: “yesterday”, writable: false, enumerable: true, configurable: false} (不可配置,不可写)

Object.keys(deadline); // [‘date’] (可枚举)

Object.keys(obj) (ES5)

该方法是一种特殊的for-in循环。它只返回当前对象的属性(不像for-in),而且这些属性也必须是可枚举的(这点和Object.getOwnPropertyNames()不同,不论是否可以枚举)。返回值是一个字符串数组。

Object.prototype.customProto = 101;

Object.getOwnPropertyNames(Object.prototype);

// […, “constructor”, “toLocaleString”, “isPrototypeOf”, “customProto”]

Object.keys(Object.prototype); // [‘customProto’]

var o = {own: 202};

o.customProto; // 101

Object.keys(o); // [‘own’]

最后

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值