【学习记录】JavaScript 对象所有API解析学习

125 阅读9分钟

学习文档

文章链接 : juejin.cn/post/684490…

Object es5: yanhaijing.com/es5/#282

目标

熟悉对象及api用法

创建对象

o = new Object() 创建的是函数对象
o = {} 创建的是对象

1、函数对象的原型是对象Object(原型链为:实例-->通过new构造函数-->函数对象-->对象-->null)
2、函数有prototype属性,而对象没有(象原型链:{} --> 对象 --> null)

Object 构造器可以接受任何类型的参数,并且会自动识别参数的类型,并选择更合适的构造器来完成相关操作
例如:
new Object('w').constructor
ƒ String() { [native code] }
new Object([]).constructor
ƒ Array() { [native code] }
new Object(()=>{}).constructor
ƒ Function() { [native code] }

Object构造器识别参数类型

构造器的成员

Object.prototype

该属性是所有对象的原型(包括Object对象)

Object.prototype 的成员

Object.prototype.constructor

指向用来构造该函数对象的构造器

new Object('w').constructor
ƒ String() { [native code] }
new Object([]).constructor
ƒ Array() { [native code] }
new Object(()=>{}).constructor
ƒ Function() { [native code] }
Object.prototype.constructor === Object // true
new Object().constructor === Object //true

Object.prototype.toString(radix)

该方法返回的是一个用于描述目标对象的字符串。当目标是一个Number对象时即通过Number构造函数创建的对象,可以传递一个用于进制数的参数radix,该参数radix,该参数的默认值为10。

new Number(10).toString(2) // '1010'
({a:1}).toString() // '[object Object]'

Object.prototype.toLocaleString()

方法返回一个该对象的字符串表示。此方法被用于派生对象为了特定语言环境的目的(locale-specific purposes)而重载使用。

返回值: Object toLocaleString 返回调用 toString() 的结果。

该函数提供给对象一个通用的toLocaleString 方法,即使不是全部都可以使用它。

覆盖 toLocaleString的对象

Object.prototype.valueOf()

该方法 返回值为该对象的原始值。

不同类型对象的valueOf()方法的返回值:

Array返回数组对象本身。
Boolean布尔值。
Date存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。时间戳
Function函数本身。
Number数字值。
Object对象本身。这是默认情况。
String字符串值。
Math 和 Error 对象没有 valueOf 方法。
({}).valueOf()
{}
typeof ({}).valueOf()
'object'
new Number(4).valueOf()
4
typeof (new Number(4).valueOf())
'number'

Object.prototype.hasOwnProperty(prop)

判断对象自身是否含有prop目标属性,返回布尔值

var o = {prop:1};
o.hasOwnProperty('prop'); // true
o.hasOwnProperty('toString'); // false
o.hasOwnProperty('formString'); // false

Object.prototype.isPrototypeOf(obj)

判断当前对象是否是目标对象的原型链上某个原型,返回布尔值

var s = new String('');
Object.prototype.isPrototypeOf(s); // true
String.prototype.isPrototypeOf(s); // true
Array.prototype.isPrototypeOf(s); // false

Object.prototype.propertyIsEnumerable(prop)

判断目标属性是否可被迭代,返回布尔

var a = [1,2,3];
a.propertyIsEnumerable('length'); // false
a.propertyIsEnumerable(0); // true

在ES5中附加的Object属性

属性描述符

value——当试图获取属性时所返回的值。
writable——该属性是否可写。
enumerable——该属性在for in循环中是否会被枚举
configurable——该属性是否可被删除。
set()——该属性的更新操作所调用的函数。
get()——获取属性值时所调用的函数。

数据描述符(其中属性为:enumerable,configurable,value,writable)
与存取描述符(其中属性为enumerable,configurable,set(),get())之间是有互斥关系的
在定义了set()和get()之后,描述符会认为存取操作已被 定义了,其中再定义value和writable会引起错误。

Object.defineProperty(obj, prop, descriptor)

会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

应当直接在 Object 构造器对象上调用此方法

var person = {};
Object.defineProperty(person, 'heads', {
  value: 1,
  writable: true,
  or(get(){},
  set(){}),
  enumerable:true,
  configurable:true,
});

Object.defineProperties(obj, props)

作用与defineProperty()基本相同,只不过它可以用来一次定义多个属性。

var glass = Object.defineProperties({}, {
    'color': {
        value: 'transparent',
        writable: true
    },
    'fullness': {
        value: 'half',
        writable: false
    }
});

Object.getPrototypeOf(obj)

方法返回指定对象的原型(内部[[Prototype]]属性的值)。如果没有继承属性,则返回 null

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

Object.create(obj, descr)

该方法主要用于创建一个新对象,并为其设置原型对象和原型属性。

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是原型上的自身上的属性。

Object.create(null) 创建一个完全空白的对象

Object.getOwnPropertyDescriptors(obj)

获取对象自身所有属性描述符

Object.getOwnPropertyDescriptors(Object.prototype)

Object.getOwnPropertyNames(obj)

返回一个数组,其中包含了当前对象所有属性的名称,不论该属性是否可以枚举。

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)

让一个对象变的不可扩展,也就是永远不能再添加新的属性。

const object1 = {};

Object.preventExtensions(object1);

try {
  Object.defineProperty(object1, 'property1', {
    value: 42
  });
} catch (e) {
  console.log(e);
  // expected output: TypeError: Cannot define property property1, object is not extensible
}

Object.isExtensible(obj)

检查某对象是否还可以被添加属性。

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)

Object.isSeal(obj)

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)

Object.isFrozen(obj)

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

被冻结对象自身的所有属性都不可能以任何方式被修改。任何修改尝试都会失败,无论是静默地还是通过抛出TypeError异常(最常见但不仅限于strict mode)。

数据属性的值不可更改,访问器属性(有getter和setter)也同样(但由于是函数调用,给人的错觉是还是可以修改这个属性)。如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。数组作为一种对象,被冻结,其元素不能被修改。没有数组元素可以被添加或移除。

这个方法返回传递的对象,而不是创建一个被冻结的副本。

Object.keys(obj)

会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']

// array like object with random key ordering
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']

// getFoo is a property which isn't enumerable
var myObj = Object.create({}, {
  getFoo: {
    value: function () { return this.foo; }
  }
});
myObj.foo = 1;
console.log(Object.keys(myObj)); // console: ['foo']

Object.keys("foo");
// TypeError: "foo" is not an object (ES5 code)

Object.keys("foo");
// ["0", "1", "2"]                   (ES2015 code)

在ES6中附加的Object属性

Object.is(value1, value2)

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

Object.is('xuanyuan', 'xuanyuan'); // true
Object.is({},{}); // false
Object.is(+0, -0); // false
+0 === -0; // true
Object.is(NaN, NaN); // true
NaN === NaN; // false

ES5可以通过以下代码部署Object.is

Object.defineProperty(Object, 'is', {
    value: function() {x, y} {
        if (x === y) {
           // 针对+0不等于-0的情况
           return x !== 0 || 1 / x === 1 / y;
        }
        // 针对 NaN的情况
        return x !== x && y !== y;
    },
    configurable: true,
    enumerable: false,
    writable: true
});

Object.assign(target, ...sources)

该方法用来源对象(source)的所有可枚举的属性复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象target,后面的参数都是源对象(source)。只要有一个参数不是对象,就会抛出TypeError错误。

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

Object.assign只复制自身属性,不可枚举的属性(enumerable为false)和继承的属性不会被复制。

Object.assign({b: 'c'}, 
    Object.defineProperty({}, 'invisible', {
        enumerable: true,
        value: 'hello'
    })
);
// {b: 'c'}
Object.assign({b: 'c'}, 
    Object.defineProperty({}, 'invisible', {
        enumerable: true,
        value: 'hello'
    })
);
// {b: 'c', invisible: 'hello'}

属性名为Symbol值的属性,也会被Object.assign()复制。

Object.assign({a: 'b'}, {[Symbol('c')]: 'd'});
// {a: 'b', Symbol(c): 'd'}

对于嵌套的对象,Object.assign()的处理方法是替换,而不是添加。

Object.assign({a: {b:'c',d:'e'}}, {a:{b:'hello'}});
// {a: {b:'hello'}}

对于数组,Object.assign()把数组视为属性名为0、1、2的对象。

Object.assign([1,2,3], [4,5]);
// [4,5,3]

Object.getOwnPropertySymbols(obj)

该方法会返回一个数组,该数组包含了指定对象自身的(非继承的)所有 symbol 属性键。
该方法和 Object.getOwnPropertyNames() 类似,但后者返回的结果只会包含字符串类型的属性键,也就是传统的属性名。

Object.getOwnPropertySymbols({a: 'b', [Symbol('c')]: 'd'});
// [Symbol(c)]

Object.setPrototypeOf(obj, prototype) (ES6)

该方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。
__proto__属性用来读取或设置当前对象的prototype对象。目前,所有浏览器(包括IE11)都部署了这个属性。

// ES6写法
var obj = {
    method: function(){
        // code ...
    }
};
// obj.__proto__ = someOtherObj;
// ES5写法
var obj = Object.create(someOtherObj);
obj.method = function(){
    // code ...
};

__proto__属性没有写入ES6的正文,而是写入了附录。__proto__前后的双下划线说明它本质上是一个内部属性,而不是正式对外的一个API。无论从语义的角度,还是从兼容性的角度,都不要使用这个属性。而是使用Object.setPrototypeOf()(写操作),Object.getPrototypeOf()(读操作),或Object.create()(生成操作)代替。
在实现上,__proto__调用的Object.prototype.proto
Object.setPrototypeOf()方法的作用与__proto__作用相同,用于设置一个对象的prototype对象。它是ES6正式推荐的设置原型对象的方法。

总结

通过学习JavaScript对象相关的api,对Object有了更深一层的理解,同时对原型和原型链及对象的关系更为明确。