ES6對象的擴展
ES6不僅為字符串、數值和數組帶來了擴展,也為對象帶來了很多新特性。這一節,我們來一起學習一下對象的擴展。
對象的傳統表示法
我們回顧一下,對象的傳統表示法:
1 let person = { 2 "name":"張三", 3 "say":function(){ 4 alert("你好嗎?"); 5 } 6 }
上面的案例很簡單,變量person就是一個對象,對象含有name屬性和一個say方法。表示法是用鍵值對的形式來表示,這就是傳統的表示法。
ES6中的簡潔寫法
ES6給我們帶來了更簡便的表示法,我們一起來對比一下:
1 var name = "Zhangsan"; 2 var age = 12; 3 4 //傳統的屬性寫法 5 var person = { 6 "name":name, 7 "age":age 8 }; 9 console.log(person); 10 //結果:{name: "Zhangsan", age: 12} 11 12 13 //ES6的屬性寫法 14 var person = {name,age}; 15 console.log(person); 16 //結果:{name: "Zhangsan", age: 12}
咱們來講解一下上面這個案例,首先定義兩個變量name和age,分別用傳統的寫法和ES6中的寫法,把變量作為person對象的屬性值。第一種寫法大家很熟悉,使用鍵值對的表示法,而ES6中的新寫法只是簡單地用兩個變量名即可,而得到的結果跟傳統的寫法一樣。
這也就是新的寫法更簡捷了,變量名可以作為鍵值對的鍵(變量名name和age),而變量的名作為值(變量的值Zhangsan和12),最後一起組成了person對象的內容{name:”Zhangsan”,age:12}。
對象的屬性可以這樣簡寫,那麽對象的方法表示呢?
我們來講解方法的簡寫表示法:
1 //傳統的表示法 2 var person = {3 say:function(){ 4 alert(‘這是傳統的表示法‘); 5 } 6 }; 7 8 //ES6的表示法 9 var person = { 10 say(){ 11 alert(‘這是ES6的表示法‘); 12 } 13 };
通過上面的案例,可以看出兩種寫法的區別,不管是屬性還是方法,確實ES6給我們帶來的表示法更加簡捷,代碼量更少。
屬性名可以是表達式
在表示法上除了這點改進以外,還有另外一個新特點:用字面量定義一個對象的時候,可以用表達式作為對象的屬性名或者方法名。不太明白?沒關系,來看小案例:
1 var f = "first"; 2 var n = "Name"; 3 var s = "say"; 4 var h = "Hello"; 5 6 var person = { 7 [ f+n ] : "Zhang", 8 [ s+h ](){ 9 return "你好嗎?"; 10 } 11 }; 12 console.log(person.firstName); 13 //結果:Zhang 14 console.log(person.sayHello()); 15 //結果:你好嗎?
註意上面person對象的定義,其中屬性名和方法名都是用中括號[ ]包裹著,裏面都是一個字符串相加的表達式,這就告訴我們,用字面量(大括號{ })定義對象的時候,屬性名和方法名可以是一個表達式,表達式的運算結果就是屬性名或者方法名。這點改進會使得對象在實際開發中的使用變得更加的靈活方便,贊!
介紹了對象的新的表示法,下面來介紹幾個ES6為對象新增的函數。
Object.is( )函數
函數的作用:比較兩個值是否嚴格相等,或者說全等。
也許有的初學者還不是很理解嚴格相等,我們在這裏來擴展一下:
嚴格相等和抽象相等
我們看看兩者的區別:
1 var str = ‘12‘; 2 var num = 12; 3 4 //抽象相等 5 str == num; 6 //結果:true 7 8 9 //嚴格相等 10 str === num; 11 //結果:false
可以看到,抽象相等用“==”表示,嚴格相等用|“===”表示,進行嚴格相等判斷的時候,首先要求類型是一樣的,否則會直接返回false。
所以上面的例子中,變量str和變量num一個是字符串類型,一個是數字類型,所以結果是false,而抽象相等會對類型不一致的兩個變量進行類型轉化,轉成同一類型再進行判斷。“12”轉換成數字類型得到12,再進行比較後得到的結果是true。
好了,科普完嚴格相等後我們回來看Object.is()函數,它的作用也跟嚴格相等一樣,我們來看看:
1 var str = ‘12‘; 2 var num = 12; 3 var num2 = 12; 4 5 Object.is(str,num); 6 //結果:false 7 8 Object.is(num2,num); 9 //結果:true
上述的執行結果跟我們預期的一樣,參數類型不一樣str和num進行比較,得到的結果是false。變量類型和值都一樣的num和num2進行比較,得到的結果是true。
Object.assign()函數
函數作用:將源對象的屬性賦值到目標對象上。這麽講肯定是有點抽象的,咱們用案例說話,更直觀更形象:
1 //這個充當目標對象 2 let target = {"a":1}; 3 4 //這個充當源對象 5 let origin = {"b":2,"c":3}; 6 7 Object.assign(target,origin); 8 9 //打印target對象出來看一下 10 console.log(target); 11 //結果 {a: 1, b: 2, c: 3} 12
註意輸出的結果,target對象已經不是{ a:1 }了,而是變成了{a: 1, b: 2, c: 3},經過Object.assign( )函數的處理,源對象的屬性被添加到了target對象上。這就是Object.assign( )函數的作用。
此外,Object.assign( )函數的參數還可以是多個(至少是兩個)。我們在上面的案例稍做修改,加一個參數:
1 //這個充當目標對象 2 let target = {"a":1}; 3 4 //這個充當源對象 5 let origin1 = {"b":2,"c":3}; 6 7 //這個充當源對象 8 let origin2 = {"d":4,"e":5}; 9 10 Object.assign(target,origin1,origin2); 11 12 //打印target對象出來看一下 13 console.log(target); 14 //結果 {a: 1, b: 2, c: 3, d: 4, e: 5} 15
我們從最後打印出來的結果可以看出,對象origin1和對象origin2的屬性都被添加賦值到了對象target上。也就是Object.assign( )函數參數中的源對象可以是一個或者一個以上。
那麽,如果賦值過程中,對象的屬性出現了相同的名字怎麽辦?如果這樣,後面的屬性值就會覆蓋前面的屬性值。還是上面的案例稍做修改,看代碼:
1 //這個充當目標對象 2 let target = {"a":1}; 3 4 //這個充當源對象 5 let origin1 = {"a":2}; 6 7 //這個充當源對象 8 let origin2 = {"a":3}; 9 10 Object.assign(target,origin1,origin2); 11 12 //打印target對象出來看一下 13 console.log(target); 14 //結果 {a: 3} 15
每個對象屬性都含有屬性a,它的值從1到最後變成了3,也就是Object.assign()函數處理的過程中,會把最後出現的屬性覆蓋前面的同名屬性。
巧妙利用Object.assign( )函數的功能,我們可以完成很多效果,比如:給對象添加屬性和方法,克隆對象,合並多個對象,為對象的屬性指定默認值。
Object.getPrototypeOf( )函數
函數作用:獲取一個對象的prototype屬性。這裏的對象我們用一個自定義類實例出來的對象來演示。(這裏涉及到了javascript的面向對象,後面拓展)
1 //自定義一個Person類(函數) 2 function Person(){ 3 4 } 5 //函數都有一個預屬性prototype對象 6 Person.prototype = { 7 //給prototype對象添加一個say方法 8 say(){ 9 console.log(‘hello‘); 10 } 11 }; 12 13 14 //實例化Person對象,賦值給變量allen 15 let allen = new Person(); 16 //調用類的say方法 17 allen.say(); 18 //結果:打印出hello 19 20 //獲取allen對象的prototype屬性 21 Object.getPrototypeOf(allen); 22 //結果:打印{say:function(){.....}}
這個案例代碼有點長,但是為了大家能看懂,我把註釋寫得比較詳細,前面部分都是關於面向對象的實現。把函數Person用new關鍵字調用,這個時候函數Person就相當於構造函數或者說是一個類,實例化後是一個對象,這個對象會繼承Person類的prototype的屬性和方法。上述例子中,也就是對象allen繼承了一個say方法,可以直接調用。
如果你想看看prototype中還有哪些方法和屬性,那麽,你就可以使用Object.getPrototypeOf( )函數來獲取,參數就是allen對象,最後的結果也如我們所料,確實打印出了我們剛開始定義好的內容:一個對象,含有一個say方法{say:function(){.....}}。
那麽,如果我想為這個對象修改prototype的內容,要怎麽辦?這個時候,我們可以用ES6給我們的另一個方法。
Object.setPrototypeOf()函數
函數作用:設置一個對象的prototype屬性。
還是上面的案例, 我們稍做修改:
1 //自定義一個Person類(函數) 2 function Person(){ 3 4 } 5 //函數都有一個預屬性prototype對象 6 Person.prototype = { 7 //給prototype對象添加一個say方法 8 say(){ 9 console.log(‘hello‘); 10 } 11 }; 12 13 14 //實例化Person對象,賦值給變量allen 15 let allen = new Person(); 16 //調用類的say方法 17 allen.say(); 18 //結果:打印出hello 19 20 21 //使用Object.setPrototypeOf 22 Object.setPrototypeOf( 23 allen, 24 {say(){console.log(‘hi‘)} 25 }); 26 27 //再次調用類的say方法 28 allen.say(); 29 //結果:打印出hi
上面的代碼,我們使用Object.setPrototypeOf()函數對對象的prototype屬性進行了修改,具體的修改是重寫了say方法。在修改前,我們曾經調用過一次say( )方法,得到的結果是打印hello,修改之後我們再一次調用allen.say( );得到的結果是打印出hi,說明我們修改成功了。
最後兩個函數Object.getPrototypeOf()和Object.setPrototypeOf()的案例代碼有點長,涉及到了javascript的面向對象內容。新手如果沒有接觸過面向對象的話,讀起來一定會懵逼,這裏有必要拓展一下javascript的面向對象。
javascript的面向對象
Javascript本身不是一種面向對象的編程語言,在ES5中,它的語法中也沒有class(類的關鍵字),但是,開發者可以利用對象的原型prototype屬性來模擬面向對象進行編程開發。
這裏對於新手來說不一定可以理解,但沒關系,前端君就是負責把它講明白。下面我們就用prototype模式,簡單演示一下如何模擬面向對象編程:
1 //構造函數模擬創建一個Dog類 2 function Dog(name){ 3 this.name = name; 4 } 5 6 //把一些屬性和方法,定義在prototype對象上 7 Dog.prototype = { 8 "type":"動物", 9 "say":function(){ 10 alert("名字叫"+this.name); 11 } 12 }; 13 14 //實例化 15 var dog = new Dog(‘旺財‘); 16 //調用say方法 17 dog.say(); 18 //結果:名字叫旺財
上面的案例告訴我們,模擬面向對象編程有幾個關鍵步驟:1、構造函數;2、給prototype對象添加屬性和方法;3、實例化;4、通過實例化後的對象調用類的方法或者屬性。
註意:面向對象是一種編程思想,並不是具體的工具。
本節小結
總結:ES6給我們帶來的新特性包括:簡潔的表示法、屬性名方法可以是表達式、Object.is( ) 函數、Object.assgin( ) 函數、Object.setPrototypeOf( ) 函數,Object.getPrototypeOf() 函數;此外還拓展了:嚴格相等和抽象相等的區別、javascript面向對象的實現。
ES6對象的擴展