该文章以收录: 《JavaScript深入探索之路》
前言
对象是Javascript 的基本类型。对象是一种复合值,它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值。对象也可看做是属性的无序集合。每个属性都是一个名/值对。JavaScript对象还可以从一个称为原型的对象继承属性。
<!-- more -->
需要注意的是ES6中对对象也做了一些扩展,本文章并没有特别说明,如果你想了解,可以看看阮老师的ES6书籍。
我们可以把对象的属性分为三大类
内置对象:是有ECMAScript规范定义的对象或类。例如数组、函数、日期和正则表达式都是内置对象。
宿主对象: 是由JavaScript 解析器所嵌入的宿主环境,客户端JavaScript 中表示网页结构的HTMLElement对像均是宿主对象。宿主对象也可以当成内置对象。
自定义对象:是由运行中的JavaScript 代码创建的对象。
另外还有两类属性
自有属性: 是直接在队形中定义的属性
继承属性: 是在对象的原型对象中定义的属性
创建对象
1.对象字面量(也称为对象直接量)
创建对象最简单的方式就是在JavaScripot代码中使用对象直接量。
let obj = {
name: 'web',
age: 23,
sex: 'man'
}
对象的属性名可以是Symbol
值,这时ES6新出的一个数据类型。对象直接量是一个表达式,这个表达式的每次运算都创建并初始化一个新的对象。每次计算对象直接量的时候,也都会计算它的每个属性值。也就是说,如果在一个重复调用的函数中的循环体内使用了对象直接量,它将创建很多新对象,并且每次创建的对象那个的属性值也有可能不同。
2.通过new创建的对象
new运算符创建并初始化一个新对象,关键字new
后跟随一个函数调用,这里的函数称作构造函数,构造函数用以初始化一个新创建的对象。JavaScript语言核心中的原始类型都包含内置构造函数。
let obj = new fun();
let ary = new Array();
另外我们需要知道使用new
创建的构造函数时没有原型的,但是他们最终都会继承Object.prototype
let ary = new Array();
ary.prototype // undefind
3.Object.create()方法创建对象
Object.create()
该方法创建一个新对象,它有两个参数,第一个参数是这个对象的原型。第二个参数用以对对象的属性进行进一步描述。Object.create()
是一个静态函数,而不是提供给某个对象调用的方法。
let o = {
name: 'jhon',
age: 23
}
let obj = Object.create(o);
obj.name // jhon
obj.__proto__ === o // true obj的原型链指向对象 o
obj.name === o.name // true
它的第二个参数是对属性的一些数值,下面我们会讲到,对对象属性特征的一些设置
对象的属性操作
1.查询
对象属性的查询我们有可以使用.
运算符、[]
运算符或者使用ES6提供的Reflect.get()
方法
let o = {
name: 'jhon',
age: 23
}
console.log(o.name) // 'jhon'
console.log(o['name']) // 'jhon'
console.log(Reflect.get(o, 'name')) // 'jhon'
对于[]
来说,方括号内必须是一个计算结果为字符串的表达式(也可以直接是字符串),一般我们用来获取动态的属性。另外我这里不在讲解ES6的东西,想了解ES6,可以看看阮一峰老师关于es6基础的书籍。
2.删除
delete
操作符可以删除属性,它的操作数应当是一个属性访问表达式,delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。
let o = {
name: 'jhon',
age: 23,
other: {
address: 'HangHai',
},
}
var obj = o.name;
delete o.name
console.log(o.name) // underfind
console.log(obj) // 'jhon'
另外delete
运算符只能删除自有属性,不能删除继承属性,它也不能删除某些属性配置为false的属性。还有全局函数和var
声明的变量也是不能删除的。
3.继承
属性是可以继承的,JavaScript对象具有“自有属性”,也有一些是从原型对象上继承的属性。例如函数的toString()
方法我们继承自Object的原型。
4.检测
检测属性的归属我们可以使用in
运算符, hasOwnPreperty()
和 protertyIsEnumerable()
方法。
let o = {
name: 'jhon',
age: 23,
other: {
address: 'HangHai',
},
}
//使用 in 操作符来判读属性是否是该对象的自有属性
// 或继承的属性
console.log('name' in o) // true
console.log('toString' in o) // true
//hasOwnProperty()判读属性是否是该对象的自有属性
console.log(o.hasOwnProperty('name')) // true
console.log(o.hasOwnProperty('toString')) // false
propertyIsEnumerable()
是 hasOwnProperty()
的增强版,只有检测是自有属性且这个苏醒的可枚举性为true
时它才返回true。
// toString 是不可枚举的属性
console.log(o.propertyIsEnumerable('toString')) // false
5.枚举属性
我们可以使用for/in
遍历(枚举) 属性,我们可以使用以下方法来遍历对象的自有属性
let o = {
name: 'jhon',
age: 23,
other: {
address: 'HangHai',
},
}
let obj = {}
for (prop in o){
if(o.hasOwnProperty[prop]) continue;
obj[prop] = o[prop];
}
6.属性的set和get
在ECMAScrit5中属性值是可以用一个或两个方法替代,这两个方法就是getter
和 setter
,由getter和setter定义的属性称做“存取器属性”,它不同于“数据属性”。
当程序查询存取器属性的值时,JavaScript调用getter方法(无参数)。这个方法的返回值就是属性存去表达式的值,当程序设置一个存去器属性的值时,JavaScript调用setter方法,将赋值表达式右侧的值当做参数传入setter。
和数据属性不同的是,存取器属性不具有可写性。如果属性同时具有getter和setter方法,那它是一个读/写属性,如果它只有getter方法,那么他是一个只读属性,如果它只有setter方法,那么他是一个只写属性。
定义存取器属性的最简单方法是使用对象直接量的语法:
let o = {
name: 'jhon',
age: 23,
get g(){
console.log("您已经拿到年龄")
return this.age + 10;
},
set g(value){
console.log('您设置的年龄为: '+ this.age)
},
}
console.log(o)
o.g // 您已经拿到年龄
o.g = 10 // 您设置的年龄为: 23
属性的几个特征
属性除了名字和值之外,还包含一些表示他们可写、可枚举、可配置的特性。
数据属性特性包括:
值
value
可写性
writable
默认 true可枚举性
enumerable
默认 true可配置性
configurable
默认 true
存取器属性特性包括:
读取
get
写入
set
可没举性
enumerable
可配置性
configurable
为了实现属性特性的查询和设置操作,ECMAScript5 定义了一个名为 “属性描述符”的对象
defineProperty()
设置某个属性的特性
let obj = {
name: 'jhon',
age: 23,
}
Object.defineProperty(obj,'name',{
value: 'King', // 改写默认值
writable: false, // 不可修改属性值
enumerable: true, // 可枚举该属性
configurable: true // 可配置该属性
})
console.log(obj.name); // 'King'
obj.name = 'Tom'; // 改写不会成功
console.log( obj.name); // 'King'
我们也可以设置器存取属性特性:
let obj = {
name: 'jhon',
age: 23,
}
// 我们将name设置成存取属性器
Object.defineProperty(obj,'name',{
get: function(){
return '更改为存取属性器'
},
enumerable: true, // 可枚举该属性
configurable: true // 可配置该属性
})
console.log(obj.name);
definePeoperties()
设置多个属性的特性
我们可以使用 definePeoperties()
来对多个属性的特性进行设置
let obj = {
name: 'jhon',
age: 23,
}
Object.defineProperties(obj,{
name:{
get: function(){
return '更改为存取属性器'
},
enumerable: true, // 可枚举该属性
configurable: true // 可配置该属性
},
age:{
writable: false, // 禁止改写age
}
})
console.log(obj.name); //更改为存取属性器
obj.age = 10;
console.log(obj.age) // 23
getOwnpropertyDescriptor()
获取某个对象自有属性的属性描述
let obj = {
name:'jhon'
}
let descriptor = Object.getOwnPropertyDescriptor(obj,'name');
// Object {value: "jhon", writable: true, enumerable: true, configurable: true}
console.log(descriptor)
对象的三个属性
1.原型属性
对象的原型属性是用来继承属性的,原型属性实例创建之初就设置好了,通过对象直接量创建的对象使用对象 Object.prototype
作为他们的原型,通过new创建的对象,使用构造函数prototype
属性作为它们的原型,通过Object.create()
创建的对象使用第一个参数(也可以是null)作为他们的原型
在ECMAScript5中,将对象作为参数传入Object.getPrototypeOf()
可以查看他的原型。
let obja = {
name:'jhon'
}
let proto = Object.getPrototypeOf(obja);
console.log(proto) // 返回Objcet的原型
如果想要检测一个对象是否是另一个对象的原型(或处于原型链中),可以使用isPrototypeOf()
方法。
function fun(name){
this.name = name
}
fun.prototype = function(){
console.log("原型")
}
let newFun = new fun('jhon');
// true
console.log(fun.prototype.isPrototypeOf(newFun))
// 另外我们还可以通过 instanceof 来检测一个对象是否是另一个对象的实例
console.log( newFun instanceof fun) // true
2.类属性
对象的雷属性是一个字符串,用以表示对象的类型信息,我们可以通过一种间接的方法查询它。
默认的 toString()
方法(继承自Object.prototype) 返回这种格式的字符串:[object class]
我们可以通过 Object.prototype.toString.call()
来检测对象的class
function fun (){
}
let className = Object.prototype.toString.call(fun);
console.log(className) // [object Function]
3.可扩展性
对象的可扩展性用以表示是否可以给对象添加新属相,所有内置对象和自定义对象都是显式可扩展的。
这里我们可以通过 Object.esExtensible()
,来判断该对象是否可扩展的。
let obj = {
name: 'jhon',
age: 23,
}
// true 对象obj默认是可扩展的
console.log(Object.isExtensible(obj))
如果想将对象转换为不可扩展的,可以使用 Object.preventExtensions()
let obj = {
name: 'jhon',
age: 23,
}
Object.preventExtensions(obj);
obj.address = 'BeiJing'
console.log(obj) // obj并没有多出一个address属性
console.log(Object.isExtensible(obj)) // false
注意一旦将对象转换为不可扩展的,就无法在将其转换回可扩展的了。
如果想将对象转换为不可扩展的,并且对象的所有自有属性都设置为不可配置(也就是封闭对象),可以使用 Object.seal()
判读封闭对象可以使用Object.isSealed()
如果想将对象转换为不可扩展的,对象的所有自有属性都设置为不可配置并且是只读(也就是冻结对象),可以使用 Object.frozen()
, 如果对象的存取器属性具有setter方法,存取器属性将不受影响。 使用Object.isFrozen()
来检测对象是否冻结。
Object.preventExtensions()
、Object.seal()
和Object.frozen()
都返回传入的对象。
对象的方法
所用的JavaScript对象都从Objcet.prototype
继承属性(除了那些不通过原型显示创建的对象),以下这些方法我不在详细介绍,因为他们还是比较常用的。
1.toString() 方法
2.toLocaleString() 方法
它仅仅调用了 toString()
方法并返回对应值,Date
和Number
类对该方法做了定制。
3.toJson() 方法
Objcet.prototype
实际上没有定义toJson()
方法,但对于需要执行序列化的对象来说,JSON.stringify()
方法会调用该方法。
4.valueOf 方法
当JavaScript需要将对象转换为某种原始值而非字符串的时候才会调用它。
结束
参考书籍:《JavaScript权威指南》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。