es6經常使用的使用

一,let塊級做用域

因爲js的歷史緣由。javascript裏的es6規範以前,只要函數做用域。當寫一些大型的項目代碼中,很容易產生全局變量,例如:javascript

<body>
    <button>ok</button>
    <button>ok</button>
    <button>ok</button>
    <button>ok</button>
    <script>
    var btn=document.querySelectorAll("button");
    for(var  i=0;i<btn.length;i++){
        btn[i].onclick=function(){
            alert(i)
        }
    }
    </script>
</body>

點擊每一個按鈕,都結果都是4;java

<body>
    <button>ok</button>
    <button>ok</button>
    <button>ok</button>
    <button>ok</button>
    <script>
    var btn=document.querySelectorAll("button");
    for(let  i=0;i<btn.length;i++){
        btn[i].onclick=function(){
            alert(i)
        }
    }
    </script>
</body>

0,1,2,3
當使用let定義變量的時候。點擊每一個按鈕,都結果顯示的都是對應的i值。git

如今咱們可使用let 定義塊級變量。 只在代碼塊{}內生效;
如:es6

<script>
    {
        var a=1
    }
    alert(a)
    </script>

彈1數組

<script>
    {
        let a=1
    }
    alert(a)
    </script>

報錯 app

使用塊級應該注意:
1.塊級做用域函數

for(var i = 0; i < 10; i++){}
console.log(i); //10

for(let j = 0; j < 10; j++){}
console.log(j); //"ReferenceError: j is not defined

2.不存在變量提高
會報錯,ReferenceErrorthis

console.log(a); // 輸出undefined
console.log(b); // 報錯ReferenceError
console.log(c); // 報錯ReferenceError
var a = 2;
let b = 2;

3.暫時性死區(TDZ)
只要進入當前塊級做用域,所使用的變量已經存在了,但在聲明以前都屬於死區,不可進行操做。es5

typeof x; // ReferenceError
typeof y  // undefined
let x;

4.不容許重複聲明spa

let x = 1;
let x; // "SyntaxError: Identifier 'x' has already been declared

var y = 2;
var y = 3; // y = 3

5.聲明的全局變量再也不是window的屬性

"use strict";
var a = 1;
console.log(window.a) // 1
let b = 1;
console.log(window.b) // undefined

二,const定義常量

const聲明一個只讀的常量。一旦聲明,常量的值就不能改變

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

上面代碼代表改變常量的值會報錯。

const聲明的變量不得改變值,這意味着,const一旦聲明變量,就必須當即初始化,不能留到之後賦值。

const foo;
// SyntaxError: Missing initializer in const declaration

使用const定義常量應該注意:

1,const的做用域與let命令相同:只在聲明所在的塊級做用域內有效。
2,const命令聲明的常量也是不提高,一樣存在暫時性死區,只能在聲明的位置後面使用。
3,const聲明的常量,也與let同樣不可重複聲明。

const本質:
const實際上保證的並非變量值不得改動,而是變量指向的那個內存地址不得改變。對於簡單類型的數據(數值,字符串,布爾值),值就是指向的那個內存地址,所以等同於常量。可是對於複合類型的數據(注意是對象和數組),變量指向的是內存地址,保存的只是一個指針,const只能保證這個指針是固定的,至於他指向的數據機構是否是可變的,就不能控制了,所以,將一個對象聲明爲常量是很是當心的。

const foo = {};

// 爲 foo 添加一個屬性,能夠成功
foo.prop = 123;
foo.prop // 123

// 將 foo 指向另外一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only

上面代碼中,常量foo儲存的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把foo指向另外一個地址,但對象自己是可變的,因此依然能夠爲其添加新屬性。

下面是另外一個例子。

const a = [];
a.push('Hello'); // 可執行
a.length = 0;    // 可執行
a = ['Dave'];    // 報錯
上面代碼中,常量a是一個數組,這個數組自己是可寫的,可是若是將另外一個數組賦值給a,就會報錯。

ES6 聲明變量的六種方法
ES5 只有兩種聲明變量的方法:var命令和function命令。ES6 除了添加let和const命令,後面章節還會提到,另外兩種聲明變量的方法:import命令和class命令。因此,ES6 一共有 6 種聲明變量的方法。

三,函數參數擴展

rest 參數
ES6 引入 rest 參數(形式爲...變量名),用於獲取函數的多餘參數,這樣就不須要使用arguments對象了。rest 參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。

<script>

function add(...values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

console.log(add(2, 5, 3)) // 10

</script>
注意在es6中rest參數只能夠是形參的最後一位參數。否則會報錯
<script>

function add(...values,a) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

console.log(add(2, 5, 3))

</script>

四,箭頭函數:

以前咱們定義一個函數是這樣的:

let add=function () {
    alert(123)
}
add()

如今咱們能夠改爲箭頭函數

let ale=()=>{alert(234)}
ale()
改爲箭頭函數無非就是把代碼簡寫了,應該注意一下三點:
1,把普通函數的function換成=>.
2,若是隻有一個參數,那麼()可省略不寫。
2,若是隻有一個return 那麼{}可省略不寫。
例如:

<script>
// 普通函數:

let add=function (a) {
    return a*2
}
console.log(add('hellow'))

// 改爲es6箭頭函數

let add= a => a*2
console.log(add('3'))

</script>

四,變量的解構賦值

1,數組的解構賦值
基本用法
ES6 容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構。
之前,爲變量賦值,只能直接指定值。

let a=1
let b=2
let c=3

ES6 容許寫成下面這樣。

let [a, b, c] = [1, 2, 3];

上面代碼表示,能夠從數組中提取值,按照對應位置,對變量賦值。

本質上,這種寫法屬於「模式匹配」,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。下面是一些使用嵌套數組進行解構的例子

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

若是解構不成功,變量的值就等於undefined。如下兩種狀況都屬於解構不成功,foo的值都會等於undefined。

let [foo] = [];
let [bar, foo] = [1];

五,數組

es6中數組有經常使用的四個方法依次是:
map ----映射 一個對一個
reduce -----彙總 一堆出來一個
filter -----過濾器
forEach -----循環(迭代)
1.map用法

<script>
let arr=[45 ,53,96,42,86]
let arr2=[]
arr2=arr.map(function(item){

if(item>=60){
    return "及格"
}else{
    return "不及格"
}

})
console.log(arr2)
</script>
也可改爲箭頭函數

<script>
    let arr=[84 ,53,96,42,86]
    let arr2=[]
    arr2=arr.map(item=>item>=60?"及格":"不及格")
    console.log(arr2)
</script>

循環數組,每次都乘2倍,並返回新數組

<script>
    let arr=[84 ,53,96,42,86]
    let arr2=[]
    arr2=arr.map(item=>item*2)
    console.log(arr2)
</script>

2.reduce

let arr=[2,14,31,1,4,3]
arr.reduce(function(a,b,c){
    alert(a+","+b+","+c)
})

先看彈什麼結果,依次是

圖片描述

圖片描述
圖片描述
圖片描述

圖片描述

先看結果。明顯 c參數是下標index,可是有不是0開始。

b是當前的數。
    其實a就是最終結果,把上一次算好的數當成了此次的中間結果。
    
    
    
    
let arr=[2,14,31,1,4,3]
let result=arr.reduce(function(tmp,item,index){
    return tmp+item
})
alert(result)

這就是求和的方式

reduce 流程圖
圖片描述

求平均數

let arr=[2,14,31,1,4,3]
let result=arr.reduce(function(tmp,item,index){
    if(index !=arr.length-1){
//不是最後一項
        return tmp+item
    }else{
        //最後一項
        return (tmp+item)/arr.length
    }
})
alert(result)

3.filter 過濾器 留下符合條件的一部分;
經過filter裏面的function裏返回的true和false判斷留或者不留。

let arr=[2,14,31,1,4,3]

 let arr2=arr.filter(()=>{
 return true
 })
alert(arr2)
//[2,14,31,1,4,3]

由於返回的true因此都留下了

let arr=[2,14,31,1,4,3]

 let arr2=arr.filter(()=>{
 return false
 })
alert(arr2)
// [ ]

由於返回的false因此都不留下

下面的取能夠被3整除的數

let arr=[2,14,33,1,4,3,66]

let arr2=arr.filter((item)=>{
 if(item%3==0){
     return true
 }else{
     return false
 }
})
alert(arr2)
//33,3,66

因爲item%3==0自己就是布爾值,因此直接能夠return這個,即就能夠返回符合條件的數。

因此能夠寫成,

let arr=[2,14,33,1,4,3,66]

let arr2=arr.filter((item)=>{
 return item%3==0
})
alert(arr2)
//33,3,66

還能夠簡寫成箭頭函數

let arr=[2,14,33,1,4,3,66]

let arr2=arr.filter(item=>item%3==0)
alert(arr2)
//33,3,66

4.forEach 就是普通的循環,沒法就是寫法簡單一些,

let arr=[2,14,33,1,4,3,66]

   arr.forEach(item=>{
       alert(item)
   })

它第二個參數是可選的,是index

let arr=[2,14,33]

arr.forEach((item,index)=>{
    alert(index+":"+item)
})
//0:2
//1:14
//2:33

六.字符串

(一):
1.includes():返回布爾值,表示是否找到了參數字符串。
2.startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
3.endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。

includes()用法

let s = 'Hello world!';

s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true

startsWith()用法

let str="git.baidu.com"
      switch(true)
      {
          case str.startsWith('www.'):
          console.log('www網址')
              break;
          case str.startsWith('git.'):
          console.log('git網址') 
              break;
          default:
         console.log('其餘網址')
      }

endsWith()用法

let str="1.jpg"
      switch(true)
      {
          case str.endsWith('txt'):
          console.log('txt文件')
              break;
          case str.endsWith('jpg'):
          console.log('jpg文件') 
              break;
          default:
         console.log('其餘網址')
      }

(二):模板字符串 (返單引號`)

$('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);

大括號內部能夠放入任意的 JavaScript 表達式,能夠進行運算,以及引用對象屬性。

let x = 1;
let y = 2;

`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"

`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"

let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"

模板字符串之中還能調用函數。

function fn() {
  return "Hello World";
}

`foo ${fn()} bar`
// foo Hello World bar

七.class

JavaScript 語言中,生成實例對象的傳統方法是經過構造函數。下面是一個例子。

function Point(x, y) {
  this.x = x;
  this.y = y;
  console.log(this,12)
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);
console.log(typeof p.toString())

其很差的地方就是,構造函數和類混爲一談了,別的語言(java)中構造函數就是構造函數,類就是類。
並且代碼寫了兩塊,方法經過prototype添加。還有就是這個是es6以前的方式生成對象。es6以前的js裏中是沒有類的概念的,這些方式都是東拼西湊的。


寫到這裏,能夠暫時回顧一下es6以前的創造對象的時候 new 關鍵字都作了什麼。

要建立 Person 的新實例,必須使用 new 操做符。以這種方式調用構造函數實際上會經歷如下 4
個步驟:
(1) 建立一個新對象;
(2) 將構造函數的做用域賦給新對象(所以 this 就指向了這個新對象) ;
(3) 執行構造函數中的代碼(爲這個新對象添加屬性) ;
(4) 返回新對象。

new 操做符
在有上面的基礎概念的介紹以後,在加上new操做符,咱們就能完成傳統面向對象的class + new的方式建立對象,在JavaScript中,咱們將這類方式成爲Pseudoclassical。
基於上面的例子,咱們執行以下代碼

var obj = new Base();

圖片描述

new操做符具體幹了什麼呢?其實很簡單,就幹了三件事情。

var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);

第一行,咱們建立了一個空對象obj
第二行,咱們將這個空對象的__proto__成員指向了Base函數對象prototype成員對象
第三行,咱們將Base函數對象的this指針替換成obj,而後再調用Base函數,因而咱們就給obj對象賦值了一個id成員變量,這個成員變量的值是」base」,關於call函數的用法。

若是咱們給Base.prototype的對象添加一些函數會有什麼效果呢?
例如代碼以下:

Base.prototype.toString = function() {
    return this.id;
}

那麼當咱們使用new建立一個新對象的時候,根據__proto__的特性,toString這個方法也能夠作新對象的方法被訪問到。因而咱們看到了構造子中,咱們來設置‘類’的成員變量(例如:例子中的id),構造子對象prototype中咱們來設置‘類’的公共方法。因而經過函數對象和Javascript特有的__proto__與prototype成員及new操做符,模擬出類和類實例化的效果。

如今的es6中創做對象的方式就及其簡單。

class Point {
    constructor (x,y){
        this.x=x;
        this.y=y
    }

    tostring (){
        return '(' + this.x + ', ' + this.y + ')';
    }
}
let a=new Point(2,3)
alert(typeof a.tostring()) //string

上面代碼定義了一個「類」,能夠看到裏面有一個constructor方法,這就是構造方法,並且this關鍵字則表明實例對象,也就是說,es5的構造函數Point,對應es6的point類的構造方法。

point類除了構造方法,還定義了一個tostring方法。注意,定義’類‘的方法時候,前面不須要加上function這個關鍵字,直接把函數定義進去級能夠了。類外,方法之間不須要逗號分隔,加上會報錯。

ES6 的類,徹底能夠看做構造函數的另外一種寫法。

class Point {
  // ...
}

typeof Point // "function"
Point === Point.prototype.constructor // true

上面代碼代表,類的數據類型就是函數,類自己就指向構造函數。
使用的時候,也是直接對類使用new命令,跟構造函數的用法徹底一致。

class Bar {
  doStuff() {
    console.log('stuff');
  }
}

var b = new Bar();
b.doStuff() // "stuff"

構造函數的prototype屬性,在 ES6 的「類」上面繼續存在。事實上,類的全部方法都定義在類的prototype屬性上面。

class Point {
  constructor() {
    // ...
  }

  toString() {
    // ...
  }

  toValue() {
    // ...
  }
}

// 等同於

Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

在類的實例上面調用方法,其實就是調用原型上的方法。

class B {}
let b = new B();

b.constructor === B.prototype.constructor // true

上面代碼中,b是B類的實例,它的constructor方法就是B類原型的constructor方法。

因爲類的方法都定義在prototype對象上面,因此類的新方法能夠添加在prototype對象上面。Object.assign方法能夠很方便地一次向類添加多個方法。

class Point {
  constructor(){
    // ...
  }
}

Object.assign(Point.prototype, {
  toString(){},
  toValue(){}
});

prototype對象的constructor屬性,直接指向「類」的自己,這與 ES5 的行爲是一致的。

Point.prototype.constructor === Point // true

另外,類的內部全部定義的方法,都是不可枚舉的(non-enumerable)。

七,面相對象

//es5中經過構造函數建立對象
function User (name,password){
    this.name=name;
    this.password=password;
    console.log(this)
}

User.prototype.showname = function(){
    alert(this.name)
}
User.prototype.showpass = function(){
    alert(this.password)
}

var user=new User('lee','123')
user.showname()
user.showpass()

// 以前的面相對象缺點:
// 1,類和構造函數混爲一談了。
// 2.方法添加到類(構造函數)外面。

es6中建立對象

// es6
    class User { //User是類
        constructor(name,password){ //constructor是構造函數
            this.name=name;
            this.password=password
        }
        //方法寫在類裏面,並且必須不能有function,多個方法之間不能有‘,’
        showname(){
            alert(this.name)
        },
        showpass(){
            alert(this.password)
        }
    }
    var user = new User ('wang','1234')
    user.showname()
    user.showpass()

繼承:
es5中的繼承:

// 繼承es5

        function User (name,password){
            this.name=name;
            this.password=password
        }
        User.prototype.showname=function(){
            alert(this.name)
        }
        User.prototype.showpass=function(){
            alert(this.password)
        }
        function Vipuser(name,password,level){
            User.call(this,name,password)
            this.level=level
        }
        Vipuser.prototype=new User() //先new一下
        Vipuser.prototype.constructor=Vipuser;//在補一下constructor,由於constructor亂了
        Vipuser.prototype.showlevel=function(){
            alert(this.level)
        }
        var vipuser=new Vipuser('LV','2323',8)
        vipuser.showname()
        vipuser.showpass()
        vipuser.showlevel()

es6中的繼承

// 繼承es6
    class User{
        constructor(name,password){
            this.name=name;
            this.password=password;
        }
        showname(){
            alert(this.name)
        }
        showpass(){
            alert(this.password)
        }
    }
    class Vipuser extends User {
        constructor(name,password,level){
            super(name,password)//super,超類,父類。執行父級的構造函數。繼承父級的屬性,至關於es5繼承中的User.call(this,name,password)
            this.level=level
        }
        showlevel(){
            alert(this.level)
        }
    }
    var vipuser=new Vipuser('dawang','123',9)
    vipuser.showname()
    vipuser.showpass()
    vipuser.showlevel()
相關文章
相關標籤/搜索