手把手教es6,ecma2015,力求作通俗易懂的es6教程

變量聲明符let

1.1 :嚴格界定範圍和使用順序,做用域消失變量消失,必須先聲明再使用

console.log(test)//wrong
let test='1';

1.2 :重複定義

  • 禁止代碼區域中重複
let test='1'
     let test='1'//wrong
  • 思考是否能夠在switch中使用?:答案在本章最後
  • 禁止在循環體中與同名var變量重複
var test='1'
     for(let test=1;test++;test<10)
{
         alert(test)//wrong
         }

1.3 :let應用:閉包問題的優化

  • 問題1:請思考代碼執行結果 function A(){ for( a=0;a<10;a++) { ClassB=function B(){ alert(a)
    } } } A() ClassB()
  • 結果1:彈出10次 從0到9 ? 代碼執行函數定義,執行了10次定義過程,
    前1次覆蓋後1次的定義過程,每次循環均覆蓋
    內存方法區裏被寫入函數定義,發現同名函數會替換函數方法體
    在函數調用的時候 只會執行1次alert,結果1確定是錯的
  • 結果2:彈出1次 9
    結果1是錯的,那麼結果2中只彈出1次是對的
    到底彈出幾呢?循環9次最後9應該是9
    難道是彈出9?
  • 結果3:undefined
    得出這個答案的朋友基礎知識很是棒,對函數調用和內存的問題掌握的很好:
    在函數A中聲明瞭另外的內部函數B 內部B使用了外部函數A中的變量a 咱們先思考下函數調用的問題吧 變量a位於函數A中, A函數發生調用之後 A函數出棧
    A中定義的全部變量會被清空 一樣變量a消失 但是當咱們調用函數B的時候須要用到a 那麼a消失了因此是undefined
  • 正確答案:alert(10) 根據結果3得知:函數內定義了另外函數,另外函數使用了外部函數的變量
    熟悉java的同窗:是否是和java的內部類和外部類很像? 在發生函數定義的時候 javaScript引擎發現內部函數在使用這個變量
    該變量須要共享 ,不能存到棧中,由於棧中會被清空數據 對應於JAVA程序中 該變量會被存儲到內存的方法區
    和全部static變量位於同1個區域,該區域內的變量要加final關鍵字
    變量共享之後內部函數和外部函數均操做該變量的引用
    外部函數在代碼執行完畢時候注意最後還有個a++ 此刻a=10;
    此刻內部函數也在使用這個a(共享的a對象引用) 那麼內部函數在使用a(共享的a)的時候,a(共享的a)已經被修改爲10了 因此內部函數再調用,訪問a的時候 彈出alert(10)
  • 閉包解決方案1:使用函數封裝閉包代碼 形式參數接受共享變量 //使用函數封裝閉包代碼 //那麼在函數內使用的是形式參數i接受共享變量a //在發生閉包調用的時候 直接調用這個函數把共享變量傳遞進來i=a; //方法中的形式參數但是每次都出棧的,咱們操做的都是形式參數 //第一次循環操做的是形式參數i 此刻i=a,a是0那麼i=0,方法寫入方法區 //第2次循環i=a,a是1 彈出alert(i)彈出1 方法寫入方法區替換 //第10次循環i=a,a是9 彈出alert(i)是9 方法寫入方法區替換 //A執行完畢修改了a,a++此刻a=10 //可是方法區裏的方法操做的是alert(i) 再也不是a了,寫入方法區那一時刻i=9 //因此結果是alert(9) function A() { var _loop = function _loop(i) { ClassB = function B() { alert(i); }; }; for (var a = 0; a < 10; a++) { _loop(a); } } A(); ClassB();
  • 閉包解決方案優化: //每次都寫個函數定義形式參數好麻煩,使用let可完成上述操做 function A(){ for(let a=0;a<10;a++) { ClassB=function B(){ alert(a)
    } } } A() ClassB()

變量自動析構

1.4 普通賦值析構

[對象屬性.賦值的變量]=對象  
 [a.A,b.B,c]=對象  
 獲取對象的屬性a 賦值給變量A
 b同a賦值
 獲取對象的屬性c 沒有發現要賦值的變量  
 自動生成同名變量c 則c=對象c屬性對應的數值

1.5 參數傳遞析構

var func= function({a,b,c}){
  console.log(a)//獲取實際參數對象中的屬性a賦值 沒有賦值變量 生成同名變量a
  console.log(b)
  console.log(c)
 }  
 func({a:1,b:2,c:3})

對象展開符和動態參數:

1.6函數調統階段使用。。。展開

//參數展開
function sum (x, y, z) {return x+y+z }
  args=[0,1,2]
  sum(..args)//自動獲取數組args中的每1個對象而且賦值

1.7 函數定義階段使用。。。動態傳參 做爲數組接受全部參數

function sum(..x)
{
  console.log(x)
}      
  sum(1,2,3)

1.8 賦值階段使用:拷貝數據

var arr = [1,2,3];
var arr2 = [...arr];//展開[1,2,3]而且拷貝返回新的對象1,2,3

箭頭函數

1.9 在箭頭函數中實現代碼使用{},大括號表示代碼執行

(a)={alert(a)}    ==== function(a){alert(a)}

1.10 箭頭函數返回對象(),小括號表示對象返回

(a)={return a}    ==== (a)=>(a) ===function(a) {return a}

1.11 操做this

var func=(a)={alert(this)}
 this是什麼?區別於普通函數this再也不是函數調用這
p=new Person()
  p.func();//func中的this再也不是Person對象
  箭頭函數中的this是箭頭函數聲明所在類,或者所在function的對象
  箭頭函數在哪裏聲明的this就是誰  
  優勢:節省了綁定this操做  
  以往在jsx中操做點擊事件 要處理當前組件對象數據  
  須要手動bind(this)這樣才能夠訪問到當前組件  
  如今只須要用箭頭函數 自動綁定

1.12 鏈式調用

var func=(a)=>(b)=>{alert(b)}
b是什麼?  
   b是執行一次調用:func()  
   之後再次執行調用傳遞的參數  
   func()('this is b')  
   即b是用來接收第2次調用的形式參數  
   在發生調用的時候 第2次調用的參數賦值給b
  • 優勢: 使用高階函數實現柯里化操做 再調用函數時 業務更加清晰
    未柯里化: func(a,b,c) { 分別使用a,b,c處理業務 }
    func(1,2,3) 柯里化 : func(a) { a處理業務 return func(b) { b處理業務 return func(c) { c處理業務 } } } func(1)(2)(3) 即把之前須要傳遞多個參數的函數操做
    定義成只須要傳遞1個參數
    每次操做結束後再次調用 接受下1個參數
    完成之前多個參數的需求
  • 缺點: 自動生成了大量閉包,變量過多被共享到內存方法區裏注意內存泄漏

1.13 鏈式調用的應用

  • 實現異步操做:(也叫作thunk封裝)
    需求:獲取數據之後再更新HTML頁面
    使用指定api:UpdateHtml(getData())
    getData爲異步ajax獲取數據 UpdateHtml爲更新HTML
    ajax響應成功之後纔會更新 如何在調用UpdateHtml此函數的時候 不更新頁面
    讓getData再ajax獲取數據成功之後在更新頁面呢? //定義異步操做
    Update=function(){ document.getElementById('root').innerHTML="數據更新成功" } //該UpdateHtml函數此刻已經成爲異步函數 //調用它自己不會去更新dom //咱們在使用getData的時候 經過鏈式函數能夠獲取到真正的更新DOM的Update方法 //此類封裝叫作thunk var UpdateHtml=(getdata)=>{ getdata()(Update)}//調用傳遞過來的getdata函數而且執行高階調用,把更新dom的函數做爲高階函數的參數傳遞過去 //函數聲明完畢開始函數調用 //如何在getData函數裏獲取到Update方法呢? var getData=()=>assignByUpdate=>{ //getData函數發送ajax請求更新dom //經過鏈式調用 聲明assignByUpdate //該變量assignByUpdate被UpdateHtml第2次調用的時候傳遞的參數賦值 //var UpdateHtml=(getData)(Update) //assignByUpdate==Update //true ajax( success:function(){ assignByUpdate } ) } UpdateHtml(getData)
  • Redux裏使用異步action會大量使用上述的thunk操做

yield :代碼執行流程可控

1.14 定義:

給函數A標記*   
  函數被*標記之後表示該函數會被while(true)無限循環監控  
  在標記有yield的代碼的地方會暫停下來
  由於有while監控 因此當使用特殊指令的時候 代碼纔會繼續執行
  該函數會返回1個對象用於控制代碼執行流程   使用返回對象.netx()代碼纔會繼續執行
  //發現星號標記 開啓無限循環while(1)監控代碼執行步驟
  var work=function* A()
  {
 yield  console.log(1) //發現yield標記代碼會在此處中止
  console.log(2)
  console.log(3)
 }
 work.next();//從yield出繼續執行下面的代碼

1.15 對比上面的thunk封裝,yield更加簡潔

//首先在使用yiled上的函數上加*號
     //異步ajax獲取數據
     //標記yield的代碼行被javaScript引擎解析
     //代碼在此處暫停,等待接受指令
     var result=*function UpdateHTML(){
     yiled getData();
     document.getElementById('root').innerHTML="數據更新成功"
     }
     function getData(){
     if('數據查詢成功')
     {
     result.next();//發出指令 容許返回result標記*號的方法繼續從yield處執行
     //即UpdateHTML()從yield標記開始繼續執行了
     }
     }

1.16 yield應用:redux saga

如下代碼爲redux saga示例
 經過*和yield來控制代碼執行流程
 缺點:while無限循環影響性能
 import { call, put } from 'redux-saga/effects'
 export function* fetchData(action) {
 try {
 const data = yield call(Api.fetchUser, action.payload.url);
 yield put({type: "FETCH_SUCCEEDED", data});
 } catch (error) {
 yield put({type: "FETCH_FAILED", error});
 }
 }

import指令和export指令 :

1.17 export:變量導出 不一樣位置js文件變量交互

在1.js中定義了2個變量
 var name='李雷'
 var age="15"
 在2.js中如何使用這2個定義好的變量呢?  
 咱們只須要在1.js中
 var name='李雷'
 var age="12"
 //添加以下代碼
 export {name,age}  
 在2.js中使用就可使用了

1.18 import:使用導出的變量

import {name,age} from "./1.js"    
console.log(name) //'李雷'
console.log(age)//12

1.19 變量導出導入的方案:

普通導出export {name,age}
-- 使用的時候必須指定name和age:即import {name,age} from "./1.js"
-- 若是在2.js中使用的時候不想使用name和age,想用your1_name或your_age2來接受  
    1.js中的2個變量怎麼辦?
-- 使用默認導出
默認導出 export default 只支持一個變量導出  
export default name
-- 使用的時候 import any from "./1.js"  
-- any能夠任意起名  
-- console.log(any)//李雷
批量導出1.js  
-- export const name = '李雷'
-- export const age = '12'
批量導入2.js  
-- import * as types from '1.js'
使用types對象封裝1.js中全部export的變量  
export中變量的定義名字是types對象的屬性  
export中改變量的對應的數值是types對象的改屬性的數值
console.log(type)//{name:'李雷',age:'12' }

promise :異步控制:

1.20 變量導出導入的方案:

在數據狀態變化的時候,去執行預先定義好的方法
 //定義好了異步對象 分別封裝了2種狀態
 //異步函數須要傳遞個回調函數做爲狀態切換方法
 //該回調函數中2個參數resolve, reject
 //resolve是resolve(data)用於切換resolve狀態
 //reject是reject(data)用於切換reject狀態
 //data爲兩種狀態切換時傳遞的參數
 var notify=new Promise(function (resolve, reject) {
 if (ready) {
  resolve("請求成功");
 } else {
 reject("網絡出錯");
 }
 //若是對象狀態發生切換,即手動調用了resolve(data),reject(data)
 //會觸發promis對象的then中定義的對應的回調方法,即參數1函數和參數2函數
 nofity.then(func1(data){alert(data)//會顯示"請求成功"},func2(data)//會顯示"請求失敗")

代理模式(有的瀏覽器不支持Proxy):

1.21 代理模式概述

代理對象調用本身的一切方法時候均會被攔截從而實現業務操做
靜態代理:被代理的原始類方法發生變化須要手動修改地代理裏方法  
動態代理:根據被代理的原始類自動生成代理類對象,  
原始類方法變化 代理對象按照原始類生成也隨着變化  
不用手動修改,java中spring aop中用的基本都是asm動態代理

1.22 代理模式應用

代碼中有10個service類 ,之前的業務是不涉及到事務操做  
如今需求是在service中查詢數據庫的時候開啓事務和關閉事務  
那麼若是沒有代理模式 須要操做10個類文件一步一步改  
爲了不在每一個service對象中均開啓事務 關閉事務  
咱們能夠把原始的service對象修改爲代理對象,  
那麼在代理對象中查詢數據庫 等相關操做均會被攔截   
從而開啓事務 關閉事務  
咱們僅僅在1個類中修改   
就能夠完成之前在全部service對象中修改的效果

1.23 代理模式ES6應用

const target = {
name: '李雷',
       age: 15
       };
     let handler = {  
     //獲取被代理對象的屬性會調用
     get(target, key, proxy) {
     //容許方法繼續執行下去
     return Reflect.get(target, key, proxy);
     }
}
//構建代理對象
const proxy = new Proxy(target, handler);

新增長的數據結構和數組api

1.24 arrayObject.map(function(i){})

//迭代處理數組中的每一個元素i是迭代器,即每次迭代的對象

1.25 arrayObject.reduce(回調函數(p,c){},初始數值)

//若是指定了初始數值 則第一次迭代的p返回數值就是這個初始數值
  //若是沒有指定初始數值,則第一次的帶返回的p默認是0
  //c是當前指針位置元素
  //[1,2,3].reduce(function(p,c){return p+c},0)
  // 第一次迭代函數返回0,因此p=0,指針指向0號位置數值是1因此c=1
  // 第二次迭代p=上次的返回數值0+1 c是2
  //依次類推0+1+2+3是結果
  arrayObject.reduce(回調函數(p,c){},初始數值)  
  //find,filter api相似map

#類和屬性和方法定義java

1.26 使用Class定義類

class Person
     { }

1.27 定義屬性:經過構造器定義屬性,區別於java的成員變量

class Person
     {
     constructor(name) {
       this.name = name;//定義屬性name
       this.age=12 ;//定義屬性age 這點和java有所區分 不須要成員變量
      }
     }

1.28 定義類方法:方法函數不要加function

class Person
     {
       constructor(name) {
       this.name = name;//定義屬性name
       this.age=12 ;//定義屬性age 這點和java有所區分 不須要成員變量
      }
      say(){
        console.log("hello");//類中方法千萬不要加function
     }
     }

本章思考題答案

switch (i) {
 case 0:
 let a=0;
 break;
 case 1:
 let a=1; // TypeError for redeclaration.
 break;
 }
 由於switch做用域內禁止出現同名let變量
 即便break,在代碼編譯時會失效

版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證)ajax

相關文章
相關標籤/搜索