浅显易懂----javascript对象全解析(一)

前言


我先先看一下javascript权威指南中对 object的定义:

对象是一种复合值:他将很多值(原始值或者其他对象)聚合在一起,可以通过名字访问这些值。对象也可以看做是属性的无序集合,每个属性都是一个键/值对(key/value)。
我们看到的大多数引用类型值都是 Object 类型的实例;而且,Object 也是
ECMAScript 中使用最多的一个类型。对象其实就是一组数据和功能的集合。

JavaScript 中一共有六种主要类型:

• string
• number
• boolean
• null
• undefined
• object

其中基本数据类型有五种:UndefinedNullBooleanNumberString。还有 一种复杂数据类型,也就是对象-----Object

null其实表示一个空对象的指针。这也是使用 typeof 操作符检测 null 值时会返回"object"的原因
console.log(typeof null);   //object

实际上,JavaScript 中还有许多特殊的对象子类型,可以称之为复杂基本类型。

内置对象

此外,JavaScript 中还有一些对象子类型,通常被称为内置对象。有些内置对象的名字看起来和简单基础类型一样,不过实际上它们的关系更复杂:

 • String
 • Number
 • Boolean
 • Object
 • Function
 • Array
 • Date 
 • RegExp 
 • Error

内置对象将在下篇文章继续讨论。

创建对象

1.1 对象字面量表示法

创建一个名为person的对象:

let person = { 
    name : "小黄瓜", 
    age : 22 
};

在使用对象字面量语法时,属性名也可以使用字符串:

let person = { 
    "name" : "小黄瓜", 
    "age" : 22, 
};

这里的数值属性名会自动转换为字符串。

使用对象字面量语法时,如果留空花括号,则可以定义只包含默认属性和方法的对象:

let person = {};    与 new Object()相同
person.name = "小黄瓜";
person.age = 22;
1.2 使用new操作符创建对象

new操作符创建并初始化一个新对象,操作符new后面跟一个构造函数Object

let person = new Object(); 
person.name = "小黄瓜"; 
person.age = 22;
1.3 Object.create()方法
let person = Object.create({name : '小黄瓜'});
person.name   //小黄瓜

Object.create()实际上是创建了一个空对象,并将原型指针指向了传入的第一个参数。

Object.create = function(new){
    let NewObject = {};
    NewObject.prototype = new;
    return new NewObject();
}

属性的查询和设置

2.1 通过 . 的方式
let person = {
    name : '小黄瓜',
    age : 22
}
//查询值
console.log(person.name);   //小黄瓜
//设置值
person.name = 'guanguan';
console.log(person.name);    //guanguan
2.2 通过 [] 表示法
let person = {
    name : 'xiaohuanggua',
    age : 22
}
//查询值
console.log(person["name"]);  //xiaohuanggua
//设置值
person["name"] = 'guanguan';
console.log(person["name"]);  //guanguan

//但方括号语法的主要优点是可以通过变量来访问属性
let newName = "name";
console.log(person[newName]);     //guanguan
2.3 Object.keys()

返回一个数组中包含所有属性名(所有的key值)。

let person = {
    name : 'xiaohuanggua',
    age : 22
}
Object.keys(person);   //["name", "age"]
2.4 Object.values()

返回一个数组中包含所有属性值(所有的value值)。

let person = {
    name : 'xiaohuanggua',
    age : 22
}
Object.values(person);   //["xiaohuanggua", 22]

删除属性

delete运算符

可以删除对象的属性。

let person = {
    name : 'xiaohuanggua',
    age : 22
}
delete person.name;
console.log(person);   //{age: 22}

delete运算符只能删除自有属性,不可以删除继承属性(要删除继承属性必须从这个属性的原型对象上删除)。

delete运算符不能删除可配置项为false的属性。

检测属性

用于检测对象成员中的所属关系,判断某个属性是否存在于某个对象中。

3.1 in运算符

如果右侧对象的自有属性或者继承属性中包含左侧属性(字符串),则返回true,否则返回false

let person = {
    name : 'xiaohuanggua',
    age : 22
}
let test ="name" in person;
console.log(test);     //true

let test2 ="sex" in person;
console.log(test);     //false
3.2 hasOwnProperty()方法

用于判断属性是否为对象的自有属性,自有属性返回true,继承属性返回false

let person = {
    name : 'xiaohuanggua',
    age : 22
};
person.hasOwnProperty('name');    //true   person对象存在name属性
person.hasOwnProperty("sex");     //false  person对象并没有这个属性
person.hasOwnProperty("toString");   //false  这个属性是继承自Object对象  
3.3 propertyIsEnumerable()方法

只有当属性是对象的自有属性,且属性的可枚举性为true是才为true,否则为false

let person = {
    name : 'xiaohuanggua',
    age : 22
};
person.propertyIsEnumerable('name'); 
//true   person对象存在name属性且可枚举
person.propertyIsEnumerable('sex');   
//false  person对象不存在sex属性
person.propertyIsEnumerable('toString');  
//false person对象存在toString属性,但是toString不是person的自有属性,且不可枚举
3.4 !== 操作符

判断属性是否为undefined

let person = {
    name : 'xiaohuanggua',
    age : 22
};
person.name !== undefined;   //true
person.sex !== undefined;    //false
person.toString !== undefined;   //true

但是 !==操作符 不能区分不存在的属性和存在但是值为undefined的属性,而in可以很好地区分。

let person = {
    name : undefined,
};
// !==
person.name !== undefined;  //false  属性存在,但值为undefined
person.age !== undefined;   //false  属性不存在

// in
'name' in person;    //true 属性存在,但值为undefined
'age' in person;     //false  属性不存在

枚举属性

4.1 for…in
let person = {
    name : "xiaohuanggua",
    age : 22,
    sex : 'boy',
};
for(item in person){
    console.log(item);    //name,age,sex 
}
for in总是得到对象的key值。
4.2 Object.keys()

获得对象所有可见属性的属性名(key值),不包括原型中定义属性。

let person = {
    name : "xiaohuanggua",
    age : 22,
    sex : 'boy',
};
Object.keys(person);   //["name", "age", "sex"]
4.3 Object.getOwnPropertyNames()

获得对象所有属性,不包括原型中定义属性。

let person = {
    name : "xiaohuanggua",
    age : 22,
    sex : 'boy',
};
Object.getOwnPropertyNames(person);   //["name", "age", "sex"]

属性get和set

Get:在读取属性时调用的函数。默认值为 undefined

Set:在写入属性时调用的函数。默认值为 undefined

let man = {
    name:'小黄瓜',
    weibo:'@xiaohuanggua',
    get age(){
        return new Date().getFullYear()-1997;
    },
    set age(val){
        console.log('我今年'+ val);
    }
}
console.log(man.age);     //22     读取的时候调用
man.age = 1000;      //我今年1000     设置的时候调用

属性类型

数据属性和访问器属性。

6.1 数据属性

数据属性包含一个数据值的位置,在这个位置可以读取和写入值。

数据属性特性:

  1. Configurable:表示能否修改属性的特性,能否通过 delete 删除属性重新重新定义属性,或者能否把属性修改为访问器属性,这个特性默认值为 true

  2. Enumerable:表示能否通过循环返回属性(可枚举),这个特性默认值为 true

  3. Writable:表示是否可以修改属性的值。默认值为 true

  4. Value:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,
    把新值保存在这个位置。这个特性的默认值为 undefined

let person = { 
    name: "小黄瓜" ;
}; 

直接在对象上定义的属性,它们的ConfigurableEnumerableWritable都被设置为 true,而value特性被设置为指定的值。

上面的例子创建了一个名为 name 的属性,为它指定的值是"小黄瓜"。也就是说,value特性将
被设置为"小黄瓜",而对这个值的任何修改都将反映在这个地方。

而如果要修改属性默认的特性,必须使用 Object.defineProperty()方法。

这个方法接收三个参数:
属性所在的对象、属性的名字和一个对象。

其中,对象的属性必须是:configurableenumerablewritablevalue

let person = {}; 
Object.defineProperty(person, "name", { 
 writable: false, 
 value: "小黄瓜" 
}); 
alert(person.name); //"小黄瓜" 
person.name = "小绿瓜"; 
alert(person.name); //"小黄瓜" 

我们创建了一个名为 name 的属性,它的值"小黄瓜"是只读的。这个属性的值是不可修改
的,如果尝试为它指定新值,那么赋值操作无效。

let person = {}; 
Object.defineProperty(person, "name", { 
 configurable: false, 
 value: "小黄瓜" 
}); 
alert(person.name); //"小黄瓜" 
delete person.name; 
alert(person.name); //"小黄瓜" 

因为我们将 configurable 设置为 false,表示不能从对象中删除属性,所以删除操作无效。

一旦把属性定义为不可配置的,就不能再把它变回可配置了。那么再调用Object.defineProperty()方法修改除 writable 之外的特性,都会导致错误:

let person = {}; 
Object.defineProperty(person, "name", { 
 configurable: false, 
 value: "小黄瓜" 
}); 
//报错!!
Object.defineProperty(person, "name", { 
 configurable: true, 
 value: "小黄瓜" 
}); 
6.2 访问器属性

访问器属性 gettersetter 函数(这两个函数都不是必需的)。
在读取访问器属性时,会调用 getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用
setter 函数并传入新值,这个函数负责如何处理数据。

有如下 四 个特性:

  1. Configurable:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特
    性,直接在对象上定义的属性,这个特性的默认值为true
  2. Enumerable:表示能否通过循环返回属性。对于直接在对象上定义的属性,这个特性的默认值为 true
  3. Get:在读取属性时调用的函数。默认值为 undefined
  4. Set:在写入属性时调用的函数。默认值为 undefined
let person = { 
    name: '小黄瓜', 
    edition: 1 
}; 
Object.defineProperty(person, "year", { 
    get: function(){ 
        return this.name; 
    }, 
    set: function(newValue){ 
        if (newValue > 2019) { 
            this.edition = 2;
        } 
    } 
}); 

person.year = 2020; 
alert(person.edition); //2 

不一定非要同时指定 gettersetter。只指定 getter 意味着属性是不可写,写入属性会被忽略。

6.3 定义多个属性

Object.defineProperties()方法。利用这个方法可以一次定义多个属性。

这个方法接收两个对象参数:第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应。

例如:

let person = {}; 
Object.defineProperties(person, { 
    name: { 
        value: '小黄瓜' 
    }, 
 
    edition: { 
        value: 1 
    }, 
    year: { 
        get: function(){ 
            return this.name; 
        }, 
        set: function(newValue){ 
            if (newValue > 2004) { 
               this.edition = 1;
            } 
        } 
    } 
}); 

person 对象上定义了两个数据属性(nameedition)和一个访问器属性(year)。
最终的对象与之前中定义的对象相同。唯一的区别是这里的属性都是在同一时间创建的。

6.4 读取属性的特性

Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述。

这个方法接收两个参数:属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果
是访问器属性,这个对象的属性有 configurableenumerablegetset;如果是数据属性,这个对象的属性有 configurableenumerablewritablevalue

let person = {}; 
Object.defineProperties(person, { 
    name: { 
        value: '小黄瓜' 
    }, 
 
    edition: { 
        value: 1 
    }, 
    year: { 
        get: function(){ 
            return this.name; 
        }, 
        set: function(newValue){ 
            if (newValue > 2004) { 
               this.edition = 1;
            } 
        } 
    } 
}); 

let descriptor = Object.getOwnPropertyDescriptor(person, "name"); 
alert(descriptor.value); //小黄瓜 
alert(descriptor.configurable); //false 
alert(typeof descriptor.get); //"undefined"

let descriptor = Object.getOwnPropertyDescriptor(person, "year"); 
alert(descriptor.value); //undefined 
alert(descriptor.enumerable); //false 
alert(typeof descriptor.get); //"function" 

序列化对象

对象有两个方法:stringify()parse()。这两个方法分别用于把 JavaScript 对象序列化为 JSON 字符串和把 JSON 字符串解析为原生 JavaScript 值。

//对象转字符串
let obj = {x:1,y:true,z:[1,2,3],nullVal:null};
JSON.stringify(obj);     //"{"x":1,"y":true,"z":[1,2,3],"nullVal":null}"

//如果存在undefined,则不会出现序列化中
let obj = {val:undefined,a:NaN,b:Infinity,c:new Date()};
JSON.stringify(obj);       //"{'a':null,'b':null,'c':2019-06-20T10:32:34}"

//字符串转对象
let obj = JSON.parse('{"x":1}');
obj.x;     //1

对象的属性

每一个对象都有与之相关的原型(proto)、类(class)、可扩展性(extensible)。这就是对象的三个属性。

原型属性

通过对象字面量的方式创建的对象使用Object.prototype作为它们的原型;

通过new创建的对象使用构造函数的prototype属性来作为它们的原型;

通过Object.create()来创建的对象使用第一个参数作为它们的原型。

    //想要检测一个对象是否是另一个对象的原型(或者处于原型链中),使用isPrototypeOf()方法。
    let person = {x:1,y:2};
    let newPerson = Object.create(person);
    person.isPrototypeOf(newPerson);//true
    Object.prototype.isPrototypeOf(newPerson);//true

类属性

用于表示信息对象类型。
只能通过toString()这种方法查询对象的类信息。该方法返回如下格式的字符串:
[object class]。接着提取字符串的第八个到倒数第二个位置之间的字符得到类信息。

  1. 通过内置构造函数创建的对象,其类属性与构造函数的名称相匹配。

  2. 通过对象字面量和Object.create创建的对象的类属性是 Object

  3. 自定义构造函数创建的对象的类属性也是Object

可扩展属性

用以表示是否可以向对象添加新属性。

(详情见属性类型)

对象方法

9.1 toString()方法

toString() 方法可用于将当前对象转换为字符串形式,并返回结果。

//Object
    let person = {name:'小黄瓜',age:1000};
    console.log(person.toString()); //[object Object]
//Array
    let array = ["小黄瓜", true, 12, -5];
    console.log(array.toString()); //小黄瓜,true,12,-5
9.2 toLocaleString() 方法

toLocaleString() 方法返回一个表示这个对象的本地化字符串。可根据本地时间把 Date 对象转换为字符串,并返回结果。

let date = new Date();
console.log(date.toLocaleString()); //2019/8/11 下午11:51:09
9.3 valueOf() 方法

valueOf() 方法用于返回指定对象的原始值。

// Array:返回数组对象本身
let array = ["小黄瓜", true, 12, -5];
console.log(array.valueOf());  //["小黄瓜", true, 12, -5]
console.log(array.valueOf() === array ); // true

// Object:返回对象本身
let person = {name: "小黄瓜", age: 18};
console.log(person.valueOf()); //{name: "小黄瓜", age: 18}
console.log(person.valueOf() === person ); // true
9.4 toJSON()方法

toJSON()方法返回其自身的 JSON 数据格式。

//原生 Date 对象 toJSON()方法
let d=new Date();
let n=d.toJSON();
console.log(n);  //2019-08-11T16:19:52.681Z

//任何对象添加 toJSON()方法
 let book = { 
    "title": "Professional JavaScript", 
     "authors": [ 
        "Nicholas C. Zakas" 
    ], 
    edition: 3, 
    year: 2011, 
    toJSON: function(){ 
        return this.title; 
    } 
 }; 
 
let jsonText = JSON.stringify(book); 
console.log(jsonText);  //"Professional JavaScript"

toJSON()可以作为函数过滤器的补充。假设把一个对象传入JSON.stringify(),序列化该对象的顺序如下:

1. 如果存在 toJSON()方法而且能通过它取得有效的值,则调用该方法。否则,返回对象本身。
2. 如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第一步返回的值。
3. 对第二步返回的每个值进行相应的序列化。
4. 如果提供了第三个参数,执行相应的格式化。

关于对象的上半部分已经完结,下一篇还会远吗…

本文参考:

Javascript高级程序设计(第三版)

Javascript权威指南(第六版)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值