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

前言javascript


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

对象是一种复合值:他将不少值(原始值或者其余对象)聚合在一块儿,能够经过名字访问这些值。对象也能够看作是属性的无序集合,每一个属性都是一个键/值对(key/value)。 咱们看到的大多数引用类型值都是 Object 类型的实例;并且,Object 也是 ECMAScript 中使用最多的一个类型。对象其实就是一组数据和功能的集合。json

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

• string
• number
• boolean
• null
• undefined
• object
复制代码

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

null其实表示一个空对象的指针。这也是使用 typeof 操做符检测 null 值时会返回"object"的缘由 ui

console.log(typeof null);   //object
复制代码

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

内置对象

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

• String
 • Number
 • Boolean
 • Object
 • Function
 • Array
 • Date 
 • RegExp 
 • Error
复制代码

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

建立对象

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权威指南(第六版)

相关文章
相关标签/搜索