ES6 新特性
一、ES6簡介
歷時將近6年的時間來制定的新 ECMAScript 標(biāo)準(zhǔn) ECMAScript 6(亦稱 ECMAScript Harmony叫挟,簡稱 ES6)終于在 2015 年 6 月正式發(fā)布。自從上一個標(biāo)準(zhǔn)版本 ES5 在 2009 年發(fā)布以后限煞,ES6 就一直以**新語法**抹恳、**新特性**的優(yōu)越性吸引著眾多 JavaScript 開發(fā)者,驅(qū)使他們積極嘗鮮署驻。
由于ES6是在2015年發(fā)布的奋献,所以也叫ES2015。
以后ESCMAScript標(biāo)準(zhǔn)一年一更新硕舆,統(tǒng)一使用年份命名:ES2016秽荞、ES2017、....
下面開始介紹ES6常用的一些新特性:
二抚官、塊級作用域綁定
在ES5之前扬跋,不存在塊級作用域,在編程的時候很多時候會帶來很多的不便凌节,ES6新增了塊級作用域钦听,補足了這方面的缺陷。
塊級聲明指的是該聲明的變量無法被代碼塊外部訪問倍奢。塊作用域朴上,又被稱為詞法作用域(lexical scopes),可以在如下的條件下創(chuàng)建:
- 函數(shù)內(nèi)部
- 在代碼塊(即 { })內(nèi)部
塊級作用域是很多類C語言的工作機制卒煞,ECMAScript 6 引入塊級聲明的目的是增強 JavaScript 的靈活性痪宰,同時又能與其它編程語言保持一致。
2.1 let聲明
使用let聲明變量的語法和使用var聲明的語法是一樣的畔裕。但是let聲明的變量的作用域會限制在當(dāng)前的代碼塊中衣撬。這是let與var的最大區(qū)別琐簇。
<script type="text/javascript">
let a = 10;
if(a > 5){
console.log(b); //用let聲明的變量沒有聲明提前這一特性蒿秦,所以此處也訪問不到(報錯)
let b = 20;
console.log(b);
}
console.log(b); //由于b是在if塊中使用let聲明的,所以此處無法訪問到周崭。(報錯)
</script>
注意:
- 用 let 聲明的變量具有塊級作用域甜无,只能在聲明的塊中訪問扛点,在塊外面無法訪問
- 用let聲明的變量也沒有聲明提前這一特性。
- 在同一個塊中岂丘,let聲明的變量也不能重復(fù)聲明陵究。
- 在聲明變量的時候盡量使用let,慢慢的拋棄var
2.2 const聲明(Constant Declarations)
在 ES6 使用const來聲明的變量稱之為常量奥帘。這意味著它們不能再次被賦值畔乙。由于這個原因,所有的 const 聲明的變量都必須在聲明處初始化翩概。
const聲明的常量和let變量一樣也是具有塊級作用域的特性牲距。
<script type="text/javascript">
var a = 20;
if (true) {
const b = 20;
b = 30; //錯誤! 常量不能重新賦值
const c; //錯誤返咱! 常量聲明的同時必須賦值。
}
</script>
注意:
- const的特性除了聲明的是常量為牍鞠,其他與let一樣咖摹。
- 在let和const聲明前的這段區(qū)域稱之為暫存性死區(qū)(The Temporal Dead Zone —TDZ)。
- 使用let和const聲明的變量和常量不再是window的屬性难述。 也就是說通過window.a是無法訪問到的萤晴。
2.3 循環(huán)中的塊級綁定
使用var聲明的循環(huán)變量在循環(huán)結(jié)束后仍然可以訪問到。 使用let聲明的循環(huán)變量胁后,在循環(huán)結(jié)束之后會立即銷毀店读。
<script type="text/javascript">
for(let i = 0; i < 3; i++){ // 循環(huán)結(jié)束之后會立即銷毀 i
console.log(i);
}
console.log(i); //此處無法訪問到 i 。
</script>
2.4 循環(huán)中的函數(shù)
看下面的代碼攀芯,是輸出10個10屯断,而不是0,1侣诺,2殖演,...
<script type="text/javascript">
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i);
});
}
funcs.forEach(function (func) {
func(); // 輸出 "10" 共10次
});
</script>
解決辦法需要使用函數(shù)的自執(zhí)行特性。
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs.push((function(value) {
return function() {
console.log(value);
}
}(i)));
}
funcs.forEach(function(func) {
func(); // 輸出 0年鸳,1趴久,2 ... 9
});
如果使用let聲明變量,則完全可以避免前面的問題搔确。 這是ES6規(guī)范中專門定義的特性彼棍。在for … in和for ... of循環(huán)中也適用
<script type="text/javascript">
var funcs = [];
for (let i = 0; i < 10; i++) {
funcs.push(function () {
console.log(i);
});
}
funcs.forEach(function (func) {
func(); // 輸出 0,1膳算,2 ... 9
})
</script>
說明:
- let 聲明使得每次迭代都會創(chuàng)建一個變量 i滥酥,所以循環(huán)內(nèi)部創(chuàng)建的函數(shù)會獲得各自的變量 i 的拷貝。每份拷貝都會在每次迭代的開始被創(chuàng)建并被賦值畦幢。
三、函數(shù)的新增特性
3.1 帶默認(rèn)參數(shù)的函數(shù)
JavaScript函數(shù)的最大的一個特點就是在傳遞參數(shù)的時候缆蝉,參數(shù)的個數(shù)不受限制的宇葱。為了健壯性考慮,一般在函數(shù)內(nèi)部需要做一些默認(rèn)值的處理刊头。
function makeRequest(url, timeout, callback) {
timeout = timeout || 2000;
callback = callback || function() {};
}
其實上面的默認(rèn)值方法有個bug:當(dāng)timeout是0的時候也會當(dāng)做假值來處理黍瞧,從而給賦值默認(rèn)值2000.
ES6從語言層面面上增加了 默認(rèn)值的 支持≡樱看下面的代碼:
//這個函數(shù)如果只傳入第一個參數(shù)印颤,后面兩個不傳入,則會使用默認(rèn)值穿肄。如果后面兩個也傳入了參數(shù)年局,則不會使用默認(rèn)值际看。
function makeRequest(url, timeout = 2000, callback = function() {}) {
// 其余代碼
}
3.2 默認(rèn)參數(shù)對 arguments 對象的影響
在非嚴(yán)格模式下,arguments總是能反映出命名參數(shù)的變化矢否≈倜觯看下面的代碼:
<script type="text/javascript">
function foo(a, b) {
//非嚴(yán)格模式
console.log(arguments[0] === a); //true
console.log(arguments[1] === b); //true
a = 10;
b = 20;
console.log(arguments[0] === a); //true
console.log(arguments[1] === b); //true
}
foo(1, 2);
</script>
在ES5的嚴(yán)格模式下,arguments只反映參數(shù)的初始值僵朗,而不再反映命名參數(shù)的變化赖欣!
<script type="text/javascript">
function foo(a, b) {
//嚴(yán)格模式
"use strict"
console.log(arguments[0] === a); //true
console.log(arguments[1] === b); //true
a = 10;
b = 20;
console.log(arguments[0] === a); //false。 修改a的值不會影響到arguments[0]的值
console.log(arguments[1] === b); //false
}
foo(1, 2);
</script>
當(dāng)使用ES6參數(shù)默認(rèn)值的時候验庙,不管是否是在嚴(yán)格模式下顶吮,都和ES5的嚴(yán)格模式相同》嘌Γ看下面的代碼:
<script type="text/javascript">
function foo(a, b = 30) {
console.log(arguments[0] === a); //true
console.log(arguments[1] === b); //true
a = 10;
b = 20;
console.log(arguments[0] === a); //false悴了。 由于b使用了默認(rèn)值。雖然a沒有使用默認(rèn)值汗菜,但是仍然表現(xiàn)的和嚴(yán)格模式一樣让禀。
console.log(arguments[1] === b); //false。 b使用了默認(rèn)值陨界,所以表現(xiàn)的和嚴(yán)格模式一樣巡揍。
}
foo(1, 2);
</script>
注意:如果這樣調(diào)用foo(1),則 a == 1, b == 30菌瘪, arguments[0] == 1, arguments[1] == undefined腮敌。也就是說默認(rèn)值并不會賦值給arguments參數(shù)。
3.3 默認(rèn)參數(shù)表達(dá)式 (Default Parameter Expressions)
參數(shù)的默認(rèn)值俏扩,也可以是一個表達(dá)式或者函數(shù)調(diào)用等糜工。看下面的代碼
<script type="text/javascript">
function getValue() {
return 5;
}
function add(first, second = getValue()) { //表示使用getValue這個函數(shù)的返回值作為second的默認(rèn)值录淡。
return first + second;
}
console.log(add(1, 1)); // 2. 調(diào)用add函數(shù)的時候捌木,傳入了第二個參數(shù),則以傳入的參數(shù)為準(zhǔn)嫉戚。
console.log(add(1)); // 6刨裆。 調(diào)用add函數(shù)的時候,沒有傳入第二個參數(shù)彬檀,則會調(diào)用getValue函數(shù)帆啃。
</script>
有一點需要要注意:getValue()只會在調(diào)用add且不傳入第二個參數(shù)的時候才會去調(diào)用。不是在解析階段調(diào)用的窍帝。
<script type="text/javascript">
let value = 5;
function getValue() {
return value++;
}
function add(first, second = getValue()) { //
return first + second;
}
console.log(add(1, 1)); // 2
console.log(add(1)); // 6努潘。
console.log(add(1)); // 7
console.log(add(1)); // 8
</script>
由于默認(rèn)值可以表達(dá)式,所以我們甚至可以使用前面的參數(shù)作為后面參數(shù)的默認(rèn)值。
function add(first, second = first) { // 使用第一個參數(shù)作為第二個參數(shù)的默認(rèn)值
return first + second;
}
注意:可以把前面的參數(shù)作為后面參數(shù)的默認(rèn)值疯坤,但是不能把后面的參數(shù)作為第一個參數(shù)的默認(rèn)值报慕。這可以前面說的let和const的暫存性死區(qū)一個意思。
function add(first = second, second)) { // 這種寫法是錯誤的
return first + second;
}
3.4 未命名參數(shù)問題
Javascript并不限制傳入的參數(shù)的數(shù)量贴膘。在調(diào)用函數(shù)的時候卖子,傳入的實參的個數(shù)超過形參的個數(shù)的時候,超過的部分就成為了未命名參數(shù)刑峡。在ES5之前洋闽,我們一般可以通過arguments對象來獲取到未命名參數(shù)的值。但是==略顯繁瑣==突梦。
<script type="text/javascript">
function foo(a) {
console.log(a);
console.log(arguments[1]) //取得傳入的多余的參數(shù)诫舅。
}
foo(2, 3);
</script>
ES6,提供了一種更加優(yōu)雅處理未命名參數(shù)的問題:剩余參數(shù)( Rest Parameters )
語法:function a(a, … b){ }
剩余參數(shù)使用三個點( … )和變量名來表示宫患。
<script type="text/javascript">
function foo(a, ...b) {
console.log(a);
console.log(b instanceof Array); //true .多余的參數(shù)都被放入了b中刊懈。b其實就是一個數(shù)組。
}
foo(2, 3, 4, 6);
</script>
注意:
- 函數(shù)最多只能有一個剩余參數(shù)b娃闲。而且這個剩余參數(shù)必須位于參數(shù)列表的最后位置虚汛。
- 雖然有了剩余參數(shù),但是arguments仍然存在皇帮,但是arguments完全無視了剩余參數(shù)的存在卷哩。
- 剩余參數(shù)是在函數(shù)聲明的時候出現(xiàn)的。
3.5 函數(shù)中的擴展運算符
例如:Math中的max函數(shù)可以返回任意多個參數(shù)中的最大值属拾。但是如果這些參數(shù)在一個數(shù)組中将谊,則沒有辦法直接傳入。以前通用的做法是使用applay方法渐白。
看下面的代碼:
<script type="text/javascript">
let values = [25, 50, 75, 100]
console.log(Math.max.apply(Math, values)); // 100
</script>
上面這種方法雖然可行尊浓,但是總是不是那么直觀。
使用ES6提供的擴展運算符可以很容易的解決這個問題纯衍。在數(shù)組前加前綴 … (三個點)栋齿。
<script type="text/javascript">
let values = [25, 50, 75, 100]
console.log(Math.max(...values)); //使用擴展運算符。相當(dāng)于拆解了數(shù)組了襟诸。
console.log(Math.max(...values, 200)); //也可以使用擴展運算符和參數(shù)的混用瓦堵,則這個時候就有 5 個數(shù)參與比較了。
</script>
注意:剩余參數(shù)和擴展運算符都是 使用三個點作為前綴励堡。但是他們使用的位置是不一樣的。
- ****剩余參數(shù)是用在函數(shù)的聲明的時候的參數(shù)列表中堡掏,而且必須在參數(shù)列表的后面
- 擴展運算符是用在函數(shù)調(diào)用的時候作為實參來傳遞的应结,在實參中的位置沒有限制。
四、全新的函數(shù):箭頭函數(shù)(=>)
ECMAScript 6 最有意思的部分之一就是箭頭函數(shù)鹅龄。正如其名揩慕,箭頭函數(shù)由 “箭頭”(=>)這種新的語法來定義。
其實在別的語言中早就有了這種語法結(jié)構(gòu)扮休,不過他們叫拉姆達(dá)表達(dá)式迎卤。
4.1 箭頭函數(shù)語法
基本語法如下:
(形參列表)=>{
//函數(shù)體
}
箭頭函數(shù)可以賦值給變量,也可以像匿名函數(shù)一樣直接作為參數(shù)傳遞玷坠。
- 示例1:
<script type="text/javascript">
var sum = (num1, num2) =>{
return num1 + num2;
}
console.log(sum(3, 4));
//前面的箭頭函數(shù)等同于下面的傳統(tǒng)函數(shù)
var add = function (num1, num2) {
return num1 + num2;
}
console.log(add(2, 4))
</script>
如果函數(shù)體內(nèi)只有一行代碼蜗搔,則包裹函數(shù)體的 大括號 ({ })完全可以省略。如果有return八堡,return關(guān)鍵字也可以省略樟凄。
如果函數(shù)體內(nèi)有多條語句,則 {} 不能省略兄渺。
- 示例2:
<script type="text/javascript">
var sum = (num1, num2) => num1 + num2;
console.log(sum(5, 4));
//前面的箭頭函數(shù)等同于下面的傳統(tǒng)函數(shù)
var add = function (num1, num2) {
return num1 + num2;
}
console.log(add(2, 4));
//如果這一行代碼是沒有返回值的缝龄,則方法的返回自也是undefined
var foo = (num1, num2) => console.log("aaa");
console.log(foo(3,4)); //這個地方的返回值就是undefined
</script>
如果箭頭函數(shù)只有一個參數(shù),則包裹參數(shù)的小括號可以省略挂谍。其余情況下都不可以省略叔壤。當(dāng)然如果不傳入?yún)?shù)也不可以省略
- 示例3:
<script type="text/javascript">
var foo = a=> a+3; //因為只有一個參數(shù),所以()可以省略
console.log(foo(4)); // 7
</script>
如果想直接返回一個js對象口叙,而且還不想添加傳統(tǒng)的大括號和return炼绘,則必須給整個對象添加一個小括號 ()
- 示例4:
<script type="text/javascript">
var foo = ()=>({name:"lisi", age:30});
console.log(foo());
//等同于下面的;
var foo1 = ()=>{
return {
name:"lisi",
age : 30
};
}
</script>
4.2 使用箭頭函數(shù)實現(xiàn)函數(shù)自執(zhí)行
<script type="text/javascript">
var person = (name => {
return {
name: name,
age: 30
}
}
)("zs");
console.log(person);
</script>
4.3 箭頭函數(shù)中無this綁定(No this Binding)
在ES5之前this的綁定是個比較麻煩的問題庐扫,稍不注意就達(dá)不到自己想要的效果饭望。因為this的綁定和定義位置無關(guān),只和調(diào)用方式有關(guān)形庭。
在箭頭函數(shù)中則沒有這樣的問題铅辞,在箭頭函數(shù)中,this和定義時的作用域相關(guān)萨醒,不用考慮調(diào)用方式
箭頭函數(shù)沒有 this 綁定斟珊,意味著 this 只能通過查找作用域鏈來確定。如果箭頭函數(shù)被另一個不包含箭頭函數(shù)的函數(shù)囊括富纸,那么 this 的值和該函數(shù)中的 this 相等囤踩,否則 this 的值為 window。
<script type="text/javascript">
var PageHandler = {
id: "123456",
init: function () {
document.addEventListener("click",
event => this.doSomething(event.type), false); // 在此處this的和init函數(shù)內(nèi)的this相同晓褪。
},
doSomething: function (type) {
console.log("Handling " + type + " for " + this.id);
}
};
PageHandler.init();
</script>
看下面的一段代碼:
<script type="text/javascript">
var p = {
foo:()=>console.log(this) //此處this為window
}
p.foo(); //輸出為 window對象堵漱。 并不是我想要的。所以在定義對象的方法的時候應(yīng)該避免使用箭頭函數(shù)涣仿。
//箭頭函數(shù)一般用在傳遞參數(shù)勤庐,或者在函數(shù)內(nèi)部聲明函數(shù)的時候使用示惊。
</script>
說明:
- 箭頭函數(shù)作為一個使用完就扔的函數(shù),不能作為構(gòu)造函數(shù)使用愉镰。也就是不能使用new 的方式來使用箭頭函數(shù)米罚。
- 由于箭頭函數(shù)中的this與函數(shù)的作用域相關(guān),所以不能使用call丈探、apply录择、bind來重新綁定this。但是雖然this不能重新綁定碗降,但是還是可以使用call和apply方法去執(zhí)行箭頭函數(shù)的隘竭。
4.4 無arguments
雖然箭頭函數(shù)沒有自己的arguments對象,但是在箭頭函數(shù)內(nèi)部還是可以使用它外部函數(shù)的arguments對象的遗锣。
<script type="text/javascript">
function foo() {
//這里的arguments是foo函數(shù)的arguments對象货裹。箭頭函數(shù)自己是沒有 arguments 對象的。
return ()=>arguments[0]; //箭頭函數(shù)的返回值是foo函數(shù)的第一個參數(shù)
}
var arrow = foo(4, 5);
console.log(arrow()); // 4
</script>
五精偿、對象功能的擴展
在JavaScript中弧圆,幾乎所有的類型都是對象,所以使用好對象笔咽,對提示JavaScript的性能很重要搔预。
ECMAScript 6 給對象的各個方面,從簡單的語法擴展到操作與交互叶组,都做了改進(jìn)拯田。
5.1 對象類別
ECMAScript 6 規(guī)范明確定義了每種對象類別。理解該術(shù)語對于從整體上認(rèn)識該門語言顯得十分重要甩十。對象類別包括:
- 普通對象(ordinary object)擁有 JavaScript 對象所有的默認(rèn)行為船庇。
- 特異對象(exotic object)的某些內(nèi)部行為和默認(rèn)的有所差異。
- 標(biāo)準(zhǔn)對象(standard object)是 ECMAScript 6 中定義的對象侣监,例如 Array, Date 等鸭轮,它們既可能是普通也可能是特異對象。
- 內(nèi)置對象(built-in object)指 JavaScript 執(zhí)行環(huán)境開始運行時已存在的對象橄霉。標(biāo)準(zhǔn)對象均為內(nèi)置對象窃爷。
5.2 對象字面量的語法擴展
5.2.1 簡寫的屬性初始化
<script type="text/javascript">
function createPerson(name, age) {
//返回一個對象:屬性名和參數(shù)名相同。
return {
name:name,
age:age
}
}
console.log(createPerson("lisi", 30)); // {name:"lisi", age:30}
//在ES6中姓蜂,上面的寫法可以簡化成如下形式
</script>
在ES6中按厘,上面的寫法可以簡化成如下的形式:
<script type="text/javascript">
function createPerson(name, age) {
//返回一個對象:屬性名和參數(shù)名相同。
return {
name, //當(dāng)對象屬性名和本地變量名相同時钱慢,可以省略冒號和值
age
}
}
console.log(createPerson("lisi", 30)); // {name:"lisi", age:30}
</script>
當(dāng)對象字面量中的屬性只有屬性名的時候逮京,JavaScript 引擎會在該作用域內(nèi)尋找是否有和屬性同名的變量。在本例中束莫,本地變量 name 的值被賦給了對象字面量中的 name 屬性懒棉。
該項擴展使得對象字面量的初始化變得簡明的同時也消除了命名錯誤御吞。對象屬性被同名變量賦值在 JavaScript 中是一種普遍的編程模式,所以這項擴展的添加非常受歡迎漓藕。
5.2.2 簡寫的方法聲明
<script type="text/javascript">
var person = {
name:'lisi',
sayHell:function () {
console.log("我的名字是:" + this.name);
}
}
person.sayHell()
</script>
在ES6中,上面的寫法可以簡化成如下的形式:
<script type="text/javascript">
var person = {
name:'李四',
sayHell() {
console.log("我的名字是:" + this.name);
}
}
person.sayHell()
</script>
省略了冒號和function看起來更簡潔
5.2.3 在字面量中動態(tài)計算屬性名
在ES5之前挟裂,如果屬性名是個變量或者需要動態(tài)計算享钞,則只能通過 對象.[變量名] 的方式去訪問。而且這種動態(tài)計算屬性名的方式 在字面量中 是無法使用的诀蓉。
<script type="text/javascript">
var p = {
name : '李四',
age : 20
}
var attName = 'name';
console.log(p[attName]) //這里 attName表示的是一個變量名栗竖。
</script>
而下面的方式使用時沒有辦法訪問到attName這個變量的。
<script type="text/javascript">
var attName = 'name';
var p = {
attName : '李四', // 這里的attName是屬性名渠啤,相當(dāng)于各級p定義了屬性名叫 attName的屬性狐肢。
age : 20
}
console.log(p[attName]) // undefined
</script>
在ES6中,把屬性名用[ ]括起來沥曹,則括號中就可以引用提前定義的變量份名。
<script type="text/javascript">
var attName = 'name';
var p = {
[attName] : '李四', // 引用了變量attName。相當(dāng)于添加了一個屬性名為name的屬性
age : 20
}
console.log(p[attName]) // 李四
</script>
5.3 新增的方法
ECMAScript 從第五版開始避免在 Object.prototype 上添加新的全局函數(shù)或方法妓美,轉(zhuǎn)而去考慮具體的對象類型如數(shù)組)應(yīng)該有什么方法僵腺。當(dāng)某些方法不適合這些具體類型時就將它們添加到全局 Object 上 。
ECMAScript 6 在全局 Object 上添加了幾個新的方法來輕松地完成一些特定任務(wù)壶栋。
5.3.1 Object.is()
在 JavaSciprt 中當(dāng)你想比較兩個值時辰如,你極有可能使用比較操作符(==)或嚴(yán)格比較操作符(===)。許多開發(fā)者為了避免在比較的過程中發(fā)生強制類型轉(zhuǎn)換贵试,更傾向于后者琉兜。但即使是嚴(yán)格等于操作符,它也不是萬能的毙玻。例如豌蟋,它認(rèn)為 +0 和 -0 是相等的,雖然它們在 JavaScript 引擎中表示的方式不同淆珊。同樣 NaN === NaN 會返回 false夺饲,所以必須使用 isNaN() 函數(shù)才能判斷 NaN 。
ECMAScript 6 引入了 Object.is() 方法來補償嚴(yán)格等于操作符怪異行為的過失施符。該函數(shù)接受兩個參數(shù)并在它們相等的返回 true 往声。只有兩者在類型和值都相同的情況下才會判為相等。如下所示:
console.log(+0 == -0); // true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
console.log(NaN == NaN); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
console.log(5 == 5); // true
console.log(5 == "5"); // true
console.log(5 === 5); // true
console.log(5 === "5"); // false
console.log(Object.is(5, 5)); // true
console.log(Object.is(5, "5")); // false
很多情況下 Object.is() 的表現(xiàn)和 === 是相同的戳吝。它們之間的區(qū)別是前者 認(rèn)為 +0 和 -0 不相等而 NaN 和 NaN 則是相同的浩销。不過棄用后者是完全沒有必要的。何時選擇 Object.is() 與 == 或 === 取決于代碼的實際情況听哭。
5.3.2 Object.assign()
使用assign主要是為了簡化對象的混入(mixin)慢洋√瘤ǎ混入是指的在一個對象中引用另一個對象的屬性或方法。
assing可以把一個對象的屬性和方法完整的轉(zhuǎn)copy到另外一個對象中普筹。
<script type="text/javascript">
var p = {
name : "lisi",
age : 20,
friends : ['張三', '李四']
}
var p1 = {};
Object.assign(p1, p); //則p1中就有了與p相同的屬性和方法. p1是接受者败明,p是提供者
console.log(p1);
//這種copy是淺copy,也就是說如果屬性值是對象的話太防,只是copy的對象的地址值(引用)
console.log(p1.friends == p.friends); //true p1和p的friends同事指向了同一個數(shù)組妻顶。
p.friends.push("王五");
console.log(p1.friends); //['張三', '李四', '王五']
</script>
assign方法可以接受任意多的提供者。意味著后面提供者的同名屬性和覆蓋前面提供者的屬性值蜒车。
<script type="text/javascript">
var p = {
name : "lisi",
age : 20,
friends : ['張三', '李四']
}
var p1 = {
name : 'zs',
}
var p2 = {};
Object.assign(p2, p, p1); //p和p1都是提供者
console.log(p2.name); // zs
</script>
六讳嘱、字符串功能的增強
6.1 查找子字符串
在以前在字符串中查找字符串的時候,都是使用indexOf方法酿愧。
ES6新增了三個方法來查找字符串沥潭。
- includes() 方法會在給定文本存在于字符串中的任意位置時返回 true,否則返回 false 嬉挡。
- startsWith() 方法會在給定文本出現(xiàn)在字符串開頭時返回 true钝鸽,否則返回 false 。
- endsWith() 方法會在給定文本出現(xiàn)在字符串末尾時返回 true庞钢,否則返回 false 寞埠。
每個方法都接收兩個參數(shù):需要搜索的文本和可選的起始索引值。
當(dāng)提供第二個參數(shù)后焊夸,includes() 和 startsWith() 會以該索引為起始點進(jìn)行匹配仁连,而 endsWith() 則是字符串搜索的結(jié)束位置。
若第二個參數(shù)未提供阱穗,includes() 和 startsWith() 會從字符串的起始中開始檢索饭冬,endsWith() 則是從字符串的末尾。
實際上揪阶,第二個參數(shù)減少了需要檢索的字符串的總量昌抠。以下是使用這些方法的演示:
var msg = "Hello world!";
console.log(msg.startsWith("Hello")); // true
console.log(msg.endsWith("!")); // true
console.log(msg.includes("o")); // true
console.log(msg.startsWith("o")); // false
console.log(msg.endsWith("world!")); // true
console.log(msg.includes("x")); // false
console.log(msg.startsWith("o", 4)); // true
console.log(msg.endsWith("o", 8)); // true
console.log(msg.includes("o", 8)); // false
6.2 repeat方法
ECMAScript 6 還向字符串添加了 repeat() 方法,它接受一個數(shù)字參數(shù)作為字符串的重復(fù)次數(shù)鲁僚。該方法返回一個重復(fù)包含初始字符串的新字符串炊苫,重復(fù)次數(shù)等于參數(shù)。例如:
console.log("x".repeat(3)); // "xxx"
console.log("hello".repeat(2)); // "hellohello"
console.log("abc".repeat(4)); // "abcabcabcabc"
6.3 字符串模板字面量
模板字面量是 ECMAScript 6 針對 JavaScript 直到 ECMAScript 5 依然缺失的如下功能的回應(yīng):
- 多行字符串 針對多行字符串的形式概念(formal concept)冰沙。
- 基本的字符串格式化 將字符串中的變量置換為值的能力侨艾。
- 轉(zhuǎn)義 HTML 能將字符串進(jìn)行轉(zhuǎn)義并使其安全地插入到 HTML 的能力。
模板字面量以一種全新的表現(xiàn)形式解決了這些問題而不需要向 JavaScript 已有的字符串添加額外的功能拓挥。
6.3.1 基本語法
使用一對反引號 ``(tab正上方的按鍵)來表示模板字面量唠梨。
let message = `Hello world!`; //使用模板字面量創(chuàng)建了一個字符串
console.log(message); // "Hello world!"
console.log(typeof message); // "string"
console.log(message.length); // 12
注意:如果模板字符串中使用到了反引號,則應(yīng)該轉(zhuǎn)義侥啤。但是單雙引號不需要轉(zhuǎn)義
6.3.2 多行字符串
在ES5之前JavaScript是不支持多行字符串的当叭。(但是在以前的版本中有一個大家都認(rèn)為是bug的方式可以寫出多行字符串茬故,就是在尾部添加一個反斜杠 \)
<body>
<script type="text/javascript">
var s = "abc \
aaaaaa";
console.log(s); //但是輸出的結(jié)果中不包括換行
</script>
</body>
但是在ES6中字符串的模板字面量輕松的解決了多行字符串的問題,而且沒有任何新的語法
<script type="text/javascript">
var s = `abc
aaaaa
dsalfja
dfadfja`;
console.log(s);
</script>
但是要注意: 反引號中的所有空格和縮進(jìn)都是有效字符蚁鳖。
6.3.3 字符串置換
置換允許你將 JavaScript 表達(dá)式嵌入到模板字面量中并將其結(jié)果作為輸出字符串中的一部分磺芭。
語法:${變量名、表達(dá)式醉箕、任意運算徘跪、方法調(diào)用等}
可以嵌入任何有效的JavaScript代碼
<script type="text/javascript">
var name = "李四";
var msg = `歡迎你${name}同學(xué)`;
console.log(msg)
</script>
6.3.4 模板標(biāo)簽
6.3.4.1 什么是模板標(biāo)簽
模板字面量真正的強大之處來源于模板標(biāo)簽。一個模板標(biāo)簽可以被轉(zhuǎn)換為模板字面量并作為最終值返回琅攘。標(biāo)簽在模板的頭部,即左 ` 字符之前指定松邪,如下所示:
let message = myTag`Hello world`;
在上面的代碼中坞琴,myTag就是模板標(biāo)簽。
myTag其實是一個函數(shù)逗抑,這個函數(shù)會被調(diào)用來處理這個模板字符串剧辐。
6.3.4.2 定義模板標(biāo)簽
一個標(biāo)簽僅代表一個函數(shù),他接受需要處理的模板字面量邮府。
標(biāo)簽分別接收模板字面量中的片段荧关,且必須將它們組合以得出結(jié)果。
函數(shù)的首個參數(shù)為包含普通 JavaScript 字符串的數(shù)組褂傀。余下的參數(shù)為每次置換的對應(yīng)值忍啤。
標(biāo)簽函數(shù)一般使用剩余參數(shù)來定義,以便輕松地處理數(shù)據(jù)仙辟。如下:
<script type="text/javascript">
let name = '張三',
age = 20,
message = show`我來給大家介紹${name}的年齡是${age}.`;
/*
應(yīng)該定義一個函數(shù)show:
參數(shù)1:一個字符串?dāng)?shù)組同波。在本例中包含三個元素。
0:"我來給大家介紹"
1:"的年齡是"
2:"."
參數(shù)2和參數(shù)3:表示需要置換的字符串的值叠国。
*/
function show(stringArr, value1, value2) {
console.log(stringArr); //
console.log(value1); // 張三
console.log(value2); // 20
return "abc";
}
console.log(message); //abc
</script>
為了簡化書寫未檩,一般把Value1和Value2寫成剩余字符串的形式
function show(stringArr, ...values){
}