es6有哪些新特性?
一、let
1. 沒有變量提升
console.log(a);
let a = 4;
// a is not defined
2. 不能重複申明
let a = 4;
let a = 5;
console.log(a);
// Identifier 'a' has already been declared
3. 臨時失效區(暫時性死區)
var a = 5;
function fn(){
console.log(a);
let a = 4;
}
fn();
// a is not defined
4. 具有塊級作用域(由花括號包裹的區域)
同樣具有塊級作用域的還有const。
來看一個例子
var a = 5;
function foo(){
console.log(a); // undefined
if(false){
var a = 6;
}
}
這顯然不是我們想要的結果,因為
js在es6之前沒有塊級作用域
for(let i = 0; i < 3; i++){
console.log(i);
}
console.log(i);
// 0 1 2 i is not defined
{
let a = 10;
}
console.log(a);
// a is not defined
老生常談的閉包問題 實質上就是為了解決沒有塊級作用域帶來的問題
閉包
* 外部函數(作用域)中有內部函數(作用域)
* 內部函數調用了外部函數的局部變量
* 外部函數執行完後,因為內部函數還在使用該局部變量,所以該局部變量不被釋放,保證內部函數正常使用
* 閉包函數(立即執行函數)為
(function(){
// ...函數體
})();
var
aLi=document.getElementsByTagName('li');// len = n
for(var i = 0; i < aLi.length; i++){
aLi[i].onclick = function(){
console.log(i);
}
}
// n......n
var aLi=document.getElementsByTagName('li');// len = n
for(var i = 0; i < aLi.length; i++){
(function(i){
aLi[i].onclick = function(){
console.log(i);
}
})(i)
}
// 0、1、2....n
for循環實質可以理解為 由n個”{}”構成的,在每個花括號中,let的作用域都是獨立的,所以可以拿到每個i值。
但對於var來說實質是一個作用域,所以無法保留每個i的值。
二、const
在es6之前,如果我們想定義常量,通常由程序員自己約定
var NUM = 100;
將所有字母都大寫的變量約定為常量,但本質還是變量
1.const定義只是地址不能修改
const NUM = 100;
NUM = 200;
// Assignment to constant variable.
由const定義的常量,無法修改其地址值。
在這裡為啥要強調是地址值
因為 以下代碼在非嚴格模式下是可以通過的
const OBJ = {a: 100};
OBJ.a = 200;
console.log(OBJ.A);
// 200
這時候會發現這很坑啊!!!
怎麼辦呢,如果我們想要定義一個常量對象呢
const OBJ = {a: 100};
Object.freeze(OBJ);
OBJ.a = 200;
console.log(OBJ.a);
// 100
這樣就可以了..
2.沒有變量提升
3.塊級作用域
let 和 const 聲明的變量不掛在window上
三、class 類
在es6之前,我們要定義一個類,只能通過function來模擬
function Person(){
this.name = 'xxx';
}
Person.prototype.say = function(){
}
var person = new Person();
問:將屬性放在原型中會怎麼樣?
如 Person.prototype.name = 'xxx';
答:對於普通數據類型,沒有問題,但對於引用類型,對一個對象的修改,會影響所有繼承該類的對象
1.語法
class Person{
constructor(name){
this.name = name;
}
say() {
console.log(this.name);
}
}
var person = new Person();
person.say();
2.繼承的實現
class Man extends Person{
constructor(name, food){
super(name, food); // 必須放在構造器的第一行,代表調用父類的構造方法
this.food = food;
}
eat(){
console.log(this.food);
}
}
var man = new Man();
man.say();
3.static 靜態方法/變量
class Person{
constructor(){
}
static say(){
console.log(123); // 可以認為這是一個靜態方法
}
static name(){
return 'xxx'; // 可以認為這是一個靜態變量
}
}
Person.say();
在es6中,規定Class 內部只有靜態方法, 沒有靜態屬性
以下寫法都無效
class Person{
constructor(){
}
name: 2
static name: 2
}
console.log(Person.name)
// undefined
四、Set 集合
Set是一個不能有重複元素的集合,重複添加無效
var s = new Set();
s.add(1);
s.add(2);
// s.delete(2) 刪除
// s.clear() 清空
// s.size() 長度
1.遍歷Set
var keys = s.keys(); // 返回一個迭代器
for(var k of keys){
console.log(k);
}
var values = s.values();
for(var v of values){
console.log(v);
}
var entries = s.entries(); // 將key和value 組合成一個數組返回
for(var e of entries){
console.log(e);
}
如果我們想在es6之前使用給數組去重
2.Array數組去重問題
方法一:
var arr = [1,2,3,4,1,1,1];
function fn(arr){
var map = {};
var newArr = arr.filter(function(item, index){
if(!map[item]){
map[item] = true;
return item;
}
});
return newArr;
}
fn(arr);
方法二:
var arr = [1,2,3,4,1,1,1];
function fn(arr){
var newArr = [];
for(var i = 0; i < arr.length; i++){
if(newArr.indexOf(arr[i]) === -1){
newArr.push(arr[i]);
}
}
return newArr;
}
fn(arr);
利用Array.from的方法三:
var arr = [1,2,3,4,1,1,1];
function fn(arr){
var s = new Set(arr);
return Array.from(s);
}
fn(arr);
3.Array返回只出現一次的元素
var arr = [1,2,3,4,1,1,1];
function fn(arr){
var newArr = [];
for(var i = 0; i < arr.length; i++){
if(arr.indexOf(arr[i]) === arr.lastIndexOf(arr[i])){
newArr.push(arr[i]);
}
}
return newArr;
}
fn(arr);
五、Map(鍵值對)
var m = new Map();
m.set('a',1);
m.set('b',2);
m.get('a'); // 1
// m.delete('a')
對象的屬性名 認為是字符串,但Map的鍵 可以是所有數據類型
forEach可以遍歷Array、Set、Map。
for of被專門用來遍歷迭代器。
六、arrow 箭頭函數
終於來到了箭頭函數的環節()=>{}
這是一種特別簡潔、優雅的函數寫法
他可以這麼寫
var fn = (item, index) => {console.log(item)}
也可以這麼寫
var fn = item => {console.log(item)}
還可以這麼寫
var fn = item => (item)
fn(2) // 2
還可以更簡潔
var fn = item => item
fn(2) // 2
=>後使用小括號() 表示將結果作為返回值,單行結果時還可以省略
當參數唯一時,還可以將前面的() 省略
但是他失去了一些東西…
var fn = () => {
console.log(arguments);
}
fn(2) // arguments is not defined
解決方法如下:
var fn = (...arg) => {
console.log(arg);
}
fn(2) // [2]
箭頭函數不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。
...稱為位擴展運算符,在下面會詳細介紹
但箭頭函數最厲害的地方還不在此
1.改變默認的this指向
箭頭函數能夠將函數外面的this指向同步到函數內部,比如說這樣:
var
aLi=document.getElementsByTagName('li');// len = n
for(var i = 0; i < aLi.length; i++){
aLi[i].onclick = function(){
setTimeout(function(){
console.log(this.innerHTML);
// 此時無法獲取,因為this指向調用他的對象,而setTimeout為window下的方法,此時this指向window
})
}
}
將function改為箭頭函數就能夠正確運行
var obj = {
a: 1,
say: function(){
console.log(this.a);
}
}
obj.say() // 1
上面乍一看這個挺正常的結果呀… 但是如果改成箭頭函數
var obj = {
a: 1,
say: () => {
console.log(this.a);
}
}
obj.say() // undefined
所以箭頭函數雖好,也要看清場合使用啊。
閱讀更多 前端亂燉 的文章
關鍵字: 鏡音雙子 編程語言 JavaScript