JavaScript原生对象-Object对象详解

JavaScript 中有个全局函数Object(),它是一个构造函数,js中所有的对象都继承Object函数的原型对象。
在浏览器中以window对象的Object方法存在,首先我们在浏览器控制台观察一下Object对象
在这里插入图片描述Object.prototype属性指向Object的原型对象,几乎所有的JS对象都是 Object 实例,JS对象会继承了Object.prototype 的属性(实际上方法也是属性)。
上图中,属性中不会被Object实例继承的属性和方法称为静态属性、静态方法,Object.prototype中的属性和方法称为实例属性、实例方法。
在这里插入图片描述

一、如何获得一个Object实例

1、Object可以作为一个普通函数,把参数转成一个对象
var obj;
//参数为undefined、null或不传参返回一个空对象
obj = Object();  //空对象
obj = Object(undefined); //空对象
obj = Object(null); //空对象
//参数是原始类型的值,Object方法将其转为对应的包装对象的实例
obj = Object(123);  //Number {123}
obj = Object('123');  //String {"123"}
obj = Object(true);  //Boolean {true}
//如果参数是一个对象,返回该对象
obj = Object([1,2,3]);  //[1, 2, 3]
obj = Object({a:1});   //{a: 1}

这种使用方式实际上很少

2、作为构造函数,创建对象实例

通过var obj = new Object()的写法生成新对象,与字面量的写法var obj = {}是等价的。

var obj = new Object();

new Object()可以接受一个参数,如果该参数是一个对象,则直接返回这个对象;
如果是一个原始类型的值,则返回该值对应的包装对象。
Object()与new Object()两者的语义是不同的,前者表示把参数value转成一个对象,后者表示生成一个Object对象实例。

3、通过字面量,创建一个对象实例
  var name='lily';
  var age=18;
  var aboutMe=function () {
    console.log('我是'+this.name+'今年'+this.age);
  };
  
  //通过构造器创建一个对象
  var p1=new Object();
  p1.name=name;
  p1.age=age;
  p1.aboutMe=aboutMe;
  console.log(p1);    //{name: "lily", age: 18, aboutMe: ƒ}
  
  //通过字面量创建一个对象
  var p2={};
  p2.name=name;
  p2.age=age;
  p2.aboutMe=aboutMe;
  console.log(p2);    //{name: "lily", age: 18, aboutMe: ƒ}

  //优化后的写法
  var p3={
    name:name,
    age:age,
    aboutMe:aboutMe
  }
  console.log(p3);    //{name: "lily", age: 18, aboutMe: ƒ}
  
  //es6写法 变量名作为属性名,变量值作为属性值
  let p4={
    name,
    age,
    aboutMe
  }
  console.log(p4);  //{name: "lily", age: 18, aboutMe: ƒ}

二、Object 的实例

Object 的实例继承Object()的prototype属性
在这里插入图片描述

1、constructor 创建对象的构造函数
2、valueOf()返回当前对象对应的值

valueOf方法的作用是返回一个对象的“值”,默认情况下返回对象本身。
PS:JavaScript 自动类型转换时会默认调用这个方法。

3、toString()返回当前对象对应的字符串形式,可以用来判断一个值的类型
var obj= new Object();
obj.toString() // "[object Object]"

上例中调用空对象的toString方法,结果返回一个字符串object Object,第二个Object表示该值的构造函数,这个例子中,obj.toString()返回"[object Object]",我们希望一个数组的实例可以返回"[object Array]",以此类推,来判断对象的类型,行不行呢?

在这里插入图片描述
通过上面的图片可以看出,并没有得到我们要的答案,这是因为数组、字符串、函数、Date 、RegExp、Function 对象都分别部署了自定义的toString方法,以字符串对象为例,其原型链上有两个toString方法
在这里插入图片描述
调用字符串的toString方法实际上是调用了String构造函数中的toString方法,返回字符串a。

为了得到类型字符串,如上例中要得到"[object String]",可以使用Object.prototype.toString方法。通过函数的call方法,帮助我们判断这个值的类型。

  Object.prototype.toString.call(1) // "[object Number]"
  Object.prototype.toString.call('a') // "[object String]"
  Object.prototype.toString.call(true) // "[object Boolean]"
  Object.prototype.toString.call(undefined) // "[object Undefined]"
  Object.prototype.toString.call(null) // "[object Null]"
  Object.prototype.toString.call(Math) // "[object Math]"
  Object.prototype.toString.call({}) // "[object Object]"
  Object.prototype.toString.call([]) // "[object Array]"
  Object.prototype.toString.call(new RegExp())  //"[object RegExp]"
  Object.prototype.toString.call(JSON)   //"[object JSON]"
4、toLocaleString() 返回当前对象对应的本地字符串形式

Object.prototype.toLocaleString方法与toString的返回结果相同,也是返回一个值的字符串形式。
PS:数组、字符Number、Date 对象都分别部署了自定义的toLocaleString方法,覆盖了Object.prototype.toLocaleString方法。
其中日期的实例对象的toString和toLocaleString返回值不一样,toLocaleString的返回值跟用户设定的所在地域相关。
在这里插入图片描述

5、hasOwnProperty() 判断某个属性是否为当前对象自有属性
var obj = {a: 1};
obj.hasOwnProperty('a');  //true
obj.hasOwnProperty('b');  //false

三、Object 的静态属性

一)对象属性模型的相关方法

1、Object.getOwnPropertyDescriptor() 和Object.getOwnPropertyDescriptors() 用于返回指定对象属性的描述

在介绍这些方法之前,请先先去了解一下JS对象属性描述符对象

Object.getOwnPropertyDescriptor()和Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptor()返回指定对象某属性的属性描述符对象;
Object.getOwnPropertyDescriptors()返回指定对象所有自身属性的描述对象。

方法参数返回值说明
Object.getOwnPropertyDescriptor()①对象 ②属性名对象返回对象某属性的描述(属性描述符对象)
Object.getOwnPropertyDescriptors()①对象对象es6新增,返回指定对象所有自身属性的描述对象
  var p={
    firstName:'Lily',
    age:18,
    lastName:'Li',
  }
  //设置属性firstName的访问器属性
  Object.defineProperty(p,'firstName',{
    get:function () {
      return 'Lilyan'
    }
  })
  //打印出对象p的属性age对应的属性描述符对象
  console.log(Object.getOwnPropertyDescriptor(p,'age'));
  //打印出对象p的所有自有属性描述符对象
  console.log(Object.getOwnPropertyDescriptors(p));

在这里插入图片描述

2、Object.defineProperty() 和Object.defineProperties() 用于添加/修改对象属性的描述
方法参数返回值说明
Object.defineProperty()①对象②属性名③属性描述符对象对象添加/修改对象指定属性的特性
Object.defineProperties()①对象 ②描述一个或多个属性描述的对象对象添加/修改对象一个或多个指定属性的特性

下面的例子中,用Object.defineProperty() 方法修改了对象p的age属性描述,让age不可枚举(不能被for in遍历)

var p={
  firstName:'Lily',
  age:18,
  lastName:'Li',
}
Object.defineProperty(p,'age',{
  enumerable:false
});
console.log(Object.getOwnPropertyDescriptor(p,'age'));  //{value: 18, writable: true, enumerable: false, configurable: true}
for(key in p){
  console.log(key+":"+p[key]);
}

接下来使用Object.defineProperties()方法,同时配置age和lastName属性,设置age为只读,lastName不可配置。

  //修改属性lastName的特性为不可配置,属性age的值不可修改
  Object.defineProperties(p,{
    age:{
      writable: false  //不可修改
    },
    lastName:{
      configurable:false //不可配置
    }
  })
  p.age=19; //静默失败
  console.log(p); //{firstName: "Lily", lastName: "Li", age: 18, aboutMe: ƒ}

lastName属性设置为不可配置,如果我们尝试去配置它时,将会报错

Object.defineProperty(p,'lastName',{
    enumerable:false
});

在这里插入图片描述
接下来为为对象p添加属性fullName属性的描述,描述中配置了get和set方法。
每次读取属性的时候会调用get方法,读取到的该属性的值为get方法的返回值。
每次给一个属性赋值的时候会调用set方法,为该属性赋的值作为参数传递给set方法。

  //为对象p添加属性fullName属性的描述
  Object.defineProperty(p, 'fullName', {
    enumerable:true,  //默认为false,不可枚举
    get: function() {
      return this.firstName+'.'+this.lastName;
    },
    // set方法能接收用户传入的值
    set: function(newName) {
      this.firstName = newName;
    }
  });
  p.fullName='Lilyan';
  console.log(Object.getOwnPropertyDescriptors(p));

在这里插入图片描述

3、Object.keys()、Object.values() 、Object.entries() 、Object.getOwnPropertyNames()
  • Object.keys() 返回一个给定对象==可枚举的自有属性(键)==组成的数组
  • Object.values() 返回一个给定对象可枚举的自有属性值组成的数组(ES6新增)
  • Object.entries() 返回一个给定对象可枚举的自有属性键值对组成的数组(ES6新增)
  • Object.getOwnPropertyNames() 返回一个给定对象对象不包括Symbol 属性全部的自有属性组成的数组

上述的4个方法,功能上比较接近,提到了可枚举、自有属性等等说法,枚举跟遍历有关,自有属性是相对于原型而言,在上面的例子中,age是个不可枚举的自有属性,我们再改造一下代码,给Object的原型对象增加一个属性a,来同时介绍一下for in的用法。

Object.prototype.a='test';
console.log(p);
//for in可以遍历出对象所有的可枚举属性(包括原型链上的属性)
for(key in p){
  console.log(key+":"+p[key]);
}

在这里插入图片描述
for…in不仅可以循环枚举自身属性还可以枚举原型链中的属性,而上述的4个方法,返回的都是可枚举的自有属性(键、值、键值对)组成的数组。

console.log(Object.keys(p));
console.log(Object.getOwnPropertyNames(p));
console.log(Object.values(p));
console.log(Object.entries(p));

在这里插入图片描述

二)控制对象状态的方法

  1. Object.preventExtensions():防止对象扩展。
  2. Object.isExtensible():判断对象是否可扩展。
  3. Object.seal():禁止对象配置。
  4. Object.isSealed():判断一个对象是否可配置。
  5. Object.freeze():冻结一个对象。
  6. Object.isFrozen():判断一个对象是否被冻结。
var p = {
  firstName:'Lily',
  lastName:'Li'
};
//1 Object.preventExtensions()使对象p不能扩展(不能增加新的属性)
Object.preventExtensions(p);
p.age=18;   //静默失败

//2 Object.isExtensible()判断对象p是否可扩展
console.log(Object.isExtensible(p)); //false

//3 Object.seal()密封一个对象,阻止添加新属性并将所有现有属性标记为不可配置
console.log(Object.getOwnPropertyDescriptor(p,'firstName'));  //属性可配置 {value: "Lily", writable: true, enumerable: true, configurable: true}
Object.seal(p);
console.log(Object.getOwnPropertyDescriptor(p,'firstName'));  //属性不可配置 {value: "Lily", writable: true, enumerable: true, configurable: false}

//4 Object.isSealed() 判断一个对象是否被密封
console.log(Object.isSealed(p)); //true

//5 Object.freeze() 冻结一个对象。一个被冻结的对象再也不能被修改,即对象属性的writable值为false
Object.freeze(p);
console.log(Object.getOwnPropertyDescriptor(p,'lastName'));  //writable属性为false {value: "Li", writable: false, enumerable: true, configurable: false}

//6 Object.isFrozen()判断一个对象是否被冻结。
console.log(Object.isFrozen(p))   //true

三)原型链相关方法

Object.create() 继承指定的对象的属性和方法去创建一个新的对象

参数:对象
返回:新对象

var p={
  lastName:'Li'
}
console.log(p)
var pp=Object.create(p);
pp.firstName='Lily';
console.log(pp)

在这里插入图片描述

Object.getPrototypeOf() 获取对象的Prototype对象(ES6新增)。

参数:对象
返回:Prototype对象

console.log(Object.getPrototypeOf(p));
console.log(Object.getPrototypeOf(pp));

上文中,多次提到了ES6,具体的详情请见ES6对象的扩展

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值