JS對象介紹
前置知識:
關于使用對象,可以先閱讀一下我的《11.使用對象》這篇文章。
#1.概念
對象是一個包含相關數據和方法的集合,由變量和方法組成,通常稱為對象的屬性和方法,比如:
let me = {
name : 'pingan',
eat: function(){
console.log('eat eat eat!!!');
}
}
其中,name
就是me
這個對象的一個屬性,eat
就是me
這個對象的一個方法。
訪問對象的屬性是這樣的:
me.name; // "pingan"
me.eat(); // "eat eat eat!!!"
另外在訪問對象屬性時,有以下兩種方式:
let me = {
name : 'pingan',
}
// 點表示法
me.name; // me.name => "pingan"
// 括號表示法
me["name"];// me.name => "pingan"
括號表示法中,必須是字符串。
我們常常這么設置對象的屬性:
let me = {
name : 'pingan',
}
// 點表示法
me.name = "leo"; // me => {name: "leo"}
// 括號表示法
me["name"] = "leo";// me => {name: "leo"}
#2.簡單的面向對象介紹
這里簡單介紹下JavaScrip的面向對象編程OOP。
面向對象編程(Object Oriented Programming,OOP,面向對象程序設計)是一種計算機編程架構。OOP 的一條基本原則是計算機程序是由單個能夠起到子程序作用的單元或對象組合而成。 —— 百度百科
我們這里定義一個簡單的對象模型,比如我,我的身上可能有很多信息(姓名,年齡,身高等等),這時候我們可以將這些信息抽取出來,像這樣:
let leo = {
name : 'leo',
age : 26,
height : 180,
}
這樣我們就將我的信息抽取成一個JS的對象了,但是這樣有個局限性,這樣定義的話,一次只能定義一個人,如果這時候,有一百個人,那么我們就需要定義一百個這樣的對象,顯然這是不可取的。
所以,這里就引入一個重要的函數——構造函數,將相同的特性封裝成通用的對象,實現定義一次,其他地方都可以使用,這也是OOP的核心思想:
// 傳入 name 參數使得可以定義任何人作為對象
function Person (name){
let me = {};
me.name = name;
me.doSomething = function(){
console.log(me.name);
}
return me;
}
創建一個函數“Person
”,只要傳入不同的name
即可得到不同的對象:
let leo = Person("leo");
leo.name; // "leo"
let pingan = Person("pingan");
pingan.name; // "pingan"
但是似乎Person
對象的定義,顯得不夠精簡,因為還要定義一個空對象來接收各個屬性和方法,幸好JavaScrip在構造函數中提供一個便捷的方法,我們將代碼改造下:
function Person (name){
this.name = name;
this.doSomething = function(){
console.log(this.name);
}
}
對于this
關鍵詞,即無論是該對象的哪個實例被構造函數創建,它的name
屬性都是參數name
的值,doSomething
方法中使用的也是參數name
。簡單理解就是用this
指代了Person
。
構造函數通常首字母大寫,用于區分普通函數。
接下來,通過new
關鍵詞,使用前面創建的構造函數(使用構造函數也叫實例化):
let leo = new Person("leo");
leo.name; // "leo"
let pingan = new Person("pingan");
pingan.name; // "pingan"
然后一個簡單的構造函數就寫好了,通常在開發的時候,可能會有很多的參數:
function Man(name, age, height, weight){
this.name = name;
this.age = age + '歲';
this.HeightAndWeight = {
height,
weight
};
this.doSomething = function (){
console.log(`
${this.name}: height:${this.HeightAndWeight.height}m,
weight:${this.HeightAndWeight.weight}Kg!!`
);
};
}
let leo = new Man("leo",25,1.8,68);
leo.doSomething(); // leo: height:1.8m, weight:68Kg!!
#3.JS中的原型
#3.1理解原型
這里需要先了解一下Object
和Function
,這兩個函數都是JS的自帶函數,Object
繼承自己,Function
繼承自己,相互繼承對方,即Object
和Function
既是函數也是對象。
console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true
Object
是 Function
的實例,而Function
是它自己的實例。
console.log(Function.prototype); // ? () { [native code] }
console.log(Object.prototype); // Object
另外,只有通過Function
創建的函數都是函數對象,其他都是普通對象(通常由Object
創建):
function f1(){};
typeof f1 //"function"
var o1 = new f1();
typeof o1 //"object"
var o2 = {};
typeof o2 //"object"
理論知識:
JavaScript 常被描述為一種基于原型的語言 (prototype-based language)——每個對象擁有一個原型對象,對象以其原型為模板、從原型繼承方法和屬性。
原型對象也可能擁有原型,并從中繼承方法和屬性,一層一層、以此類推。這種關系常被稱為原型鏈(prototype chain),它解釋了為何一個對象會擁有定義在其他對象中的屬性和方法。
準確地說,這些屬性和方法定義在Object的構造器函數(constructor functions)之上的prototype
屬性上,而非對象實例本身。
個人理解:
- JS中所有的函數對象,都有一個
prototype
屬性,對應當前對象的原型,但普通對象沒有,而prototype
屬性下還有一個constructor
,指向這個函數。
var p = {};
p.prototype; // undefined
p instanceof Object; // true
function f (){};
f.prototype; // object {constructor: ?}
f === f.prototype.constructor; // true
Object === Object.prototype.constructor; // true
- JS中所有的對象,都有一個
_proto_
屬性,指向實例對象的構造函數原型(由于_proto_
是個非標準屬性,因此只有ff和chrome兩個瀏覽器支持,標準方法是Object.getPrototypeOf()
)。
var p = new Person();
p._proto === Person.prototype; //true
修改原型:
經常我們也需要對原型進行修改:
function Person (name){
this.name = name;
}
// 添加一個getName方法
Person.prototype.getName = function(){
return "名字:" + this.name;
}
var p = new Person("leo");
p.getName(); // "名字:leo"
這里也說明了原型進行繼承,p
繼承Person
原型中新增的函數屬性getName
。
#3.2原型鏈
概念:
javascript中,每個對象都會在內部生成一個 proto
屬性,當我們訪問一個對象屬性時,如果這個對象不存在就回去 proto
指向的對象里面找,一層一層找下去,,知道找到為止,如果到了原型鏈頂端,還沒找到,則返回undefined
,這就是javascript原型鏈的概念。
總結:
- 除了
Object
的prototype
的原型是null
,所有對象和原型都有自己的原型,對象的原型指向原型對象。 - JS中所有的東西都是對象,所有的東西都由
Object
衍生而來, 即所有東西原型鏈的終點指向null。
更加詳細的介紹,可以查看下面參考文章。
#參考文章
2.JSON對象介紹
前置知識:
JSON
是一種按照JavaScript
對象語法的數據格式。
#1.概念
概念有三點:
JSON
全稱JavaScript
對象表示法(JavaScript Object Notation)。
JSON
是存儲和交換文本信息的語法。類似XML
。
JSON
比XML
更小、更快,更易解析。
———— 摘自 W3school JSON教程
JSON
使用 JavaScript
語法來描述數據對象,但是 JSON
仍然獨立于語言和平臺。JSON
解析器和 JSON
庫支持許多不同的編程語言。
#2.語法
JSON
在使用過程中可作為一個對象或者字符串存在,當作為對象時,用于獲取JSON
中的數據,而作為字符串時常用于網絡數據傳輸。
JSON
語法規則:
- 數據在名稱/值對中
- 數據由逗號分隔
- 花括號保存對象
- 方括號保存數組
通常,JSON
數據書寫格式是名稱/鍵值
:
"name" : "pingan"
而JSON
的值可以是 :
- 數字(整數或浮點數)
- 字符串(在雙引號中)
- 邏輯值(
true
或false
) - 數組(在方括號中)
- 對象(在花括號中)
null
JSON常常有三種類型:
三種類型:簡單之,對象和數組。
必須注意:JSON字符串必須是雙引號,單引號會語法錯誤。
#2.1 簡單值
簡單值可以是字符串:
"hello leo!"
也可以是數字,邏輯值:
1
#2.2 對象類型
內容放在花括號
內,是多個鍵值對。
JSON對象 與 js 對象的三個區別:
- JSON對象 必須加雙引號,而 js 對象屬性名可以不加雙引號。
- JSON對象 沒有變量聲明,而 js 對象有。
- JSON對象 沒有分號,而 js 對象有。
// js 對象
var obj = {
name : "pingan",
age : "25",
};
// json 對象
{
"name" : "pingan",
"age" : "25",
"box" : [
"a","b","c"
]
}
#2.3 數組類型
內容放在方括號
內。
JSON數組也沒有分號和變量,常常可以把JSON數組和對象結合使用,構成更復雜的數據集合。
[
{
"name" : "leo",
"age" : 25,
"box" : ["a","b","c"]
},
{
"name" : "pingan",
"age" : 25,
"box" : ["a","b","c"]
}
]
#3. 使用
JSON最常見的用法就是,從服務端獲取JSON數據,再將JSON數據轉成JavaScrip對象使用。
JSON對象有兩個方法:
-
JSON.stringify()
: 序列化操作,將JavaScript對象
轉換成JSON字符串
。 -
JSON.prase()
:反序列化操作,將JSON字符串
解析成JavaScript值
。
#3.1 序列化操作
序列化操作常常使用JSON.stringify()
。
簡單例子:
let leo = {
name : "leo",
age : 25,
box : ["a","b","c"]
}
let pingan = JSON.stringify(leo);
console.log(pingan); // "{"name":"leo","age":25,"box":["a","b","c"]}"
注意:
- 默認情況下,
JSON.stringify()
輸出的JSON字符串不包含任何空格字符或縮進,因此結果就像上面那樣。 - 序列化
JavaScript對象
時,所有函數及原型成員都會被忽略,不體現在結果上。 - 值為
undefined
的任何屬性都會被跳過。
因此,最終的值都是有效的JSON數據類型的實例屬性。
#3.2 反序列化操作
序列化操作常常使用JSON.parse()
。
簡單例子:
let copyPingan = JSON.parse(pingan);
copyPingan; // {name: "leo", age: 25, box: Array(3)}
如果傳入JSON.parse()
的字符串不是有效的JSON,則會拋出錯誤。
注意:
雖然pingan
和copyPingan
屬性相同,但兩者獨立,沒有任何關系。
#4.序列化選項
JSON.stringify()
除了要傳入序列化對象作為參數,還可以接收其他兩個參數,用來指定序列化JavaScript對象的方式:
- 過濾器:可以是個數組,也可以是個函數。
- 選項:表示是否在
JSON字符串
中保留縮進。
單獨或組合使用兩者,可以更加全面深入的控制JSON的序列化。
#4.1 過濾器
若過濾器的參數是數組,則JSON.stringify()
返回的結果將只包含數組中的屬性:
var leo = {
name : "leo",
age : 25,
box : ["a","b","c"]
}
var pingan = JSON.stringify(leo,["name","age"]);
console.log(pingan); // "{"name":"leo","age":25}"
若過濾器的參數是函數,則情況就不一樣了,傳入的函數需有兩個參數(屬性名和屬性值):
var leo = {
"name" : "leo",
"age" : 25,
"box" : ["a","b","c"]
}
var pingan = JSON.stringify(leo,function(key, value){
switch(key){
case "name":
return "我叫" + value
case "age":
return value + "歲"
default:
return value
}
});
console.log(pingan); // "{"name":"我叫leo","age":"25歲","box":["a","b","c"]}"
注意:使用switch
的時候,必須指定default
否則會返回undefined
。
#4.2 選項
JSON.stringify()
第三個參數是個選項,控制結果中的縮進和空白符。
- 若選項只有一個值,則表示每個級別縮進的空格數,最大值為
10
,超過10
則只會是10
。
var leo = {
"name" : "leo",
"age" : 25,
"box" : ["a","b","c"]
}
var pingan = JSON.stringify(leo, null, 4);
console.log(pingan);
/*
"{
"name": "leo",
"age": 25,
"box": [
"a",
"b",
"c"
]
}"
*/
[#]5.解析選項
JSON.parse()
可以接收一個函數作為參數,對每個鍵值對調用,為了跟JSON.stringify()
的過濾函數
區別,這個函數成為還原函數
。
- 若還原函數返回
undefined
,則表示要從結果中刪除對應的鍵。 - 若還原函數返回其他值,則將該值插入結果中。
還原函數接收兩個參數:屬性名和屬性值。
舉例,在日期字符串轉換為Date對象中,經常要用到還原函數:
var leo = {
"name" : "leo",
"age" : 25,
"date" : new Date(1993, 9, 9)
}
var pingan = JSON.stringify(leo);
var copy = JSON.parse(pingan,function (key, value){
// return key == "date" ? new Date(value) : value;
if(key == "date"){
return new Date(value);
}else{
return value;
}
})
console.log(copy);
// "{"name":"leo","age":25,"date":"1993-10-08T16:00:00.000Z"}"
var obj = {
name:"mumu",
age:18,
money:null,
say:function(){alert("babababa")},
family:["爸爸","媽媽","哥哥","姐姐"]
}
var str = JSON.stringify(obj);
// 將javascript 對象轉換為JSON字符串;
console.log(str);
// 把字符串 轉換為javascript 對象
var obj2 = JSON.parse(str);
console.log(obj);
console.log(obj2);
[#]參考文章
- W3school JSON教程
- 《JavaScrip高級程序設計》