ES6之解構賦值與箭頭函數的妙用

解構賦值

解構想必你們都很是瞭解吧, 無需多言。 先來看個小🌰數組

function foo(x,y,z){
  console.log(x,y,z)
}
foo(...[1,2,3])

foo.apply(null, [1,2,3])
複製代碼

還有一種狀況是 ...的另一種常見用法基本上能夠當作反向的行爲瀏覽器

function foo(x,y, ...z){
  console.log(x,y,z)
}
foo(1,2,3,4,5)  //1, 2, [3,4,5]

// 知道爲何(...args)裏面的常常這樣寫函數了
複製代碼

解構我更傾向於叫他收集:reset參數微信

function foo(...args){
  console.log(args)
}

// foo([1,2,3,4,5,])
複製代碼

如下是要注意的點:app

  • reset/gather 參數不能有默認值函數

  • 函數默認值能夠是任意合法表達式,函數調用ui

function bar(val) {
  console.log('var called')
  return y + val;
}

function foo(x = y + 3, z = bar(x)) {
  console.log(x, z)
}
var y = 5;
foo();
foo(10);
y = 6

foo(undefined, 10);

// undefined 就是缺失

複製代碼

默認值表達式是惰性求值的,是在參數的值省略或者爲 undefined 的時候this

函數聲明中形式參數是在它們本身的做用域中,能夠理解爲(...)的做用域中,而不是在函數提做用域中,這意味着在默認值表達式中的標識符引用首先匹配到形式參數做用域,而後纔會搜索外層做用域。spa

var w = 1,
  z = 2;

function foo(x = w + 1, y = x + 1, z = z + 1) {
  console.log(x, y, z)
}
foo(); //ReferenceError

複製代碼

ES6 中引入了 TDZ ,它防止變量在未初始化的狀態下被訪問.prototype

默認值表達式code

// 函數引用,而不是函數調用自己(後面沒有調用形式())

// foo 結構
function foo2() {
  return [1, 2, 3];
}

var tmp = foo2(),
  a = tmp[0],
  b = tmp[1],
  c = tmp[2]

console.log(a, b, c)
複製代碼

能夠把將數組或者對象屬性中帶索引的值手動賦值看做結構化賦值.改爲以下:

var {
  a,
  b,
  c
} = foo2()
複製代碼

注意點不該該在賦值中混入聲明,否則會出現語法錯誤。

var x = 10,
  y = 20;
[y, x] = [x, y]
console.log(x, y)
複製代碼

對象或者數組結構的賦值表達式的完成值是全部右側對象/數組的值。

var a = [2, 3, 4];
var b = [...a, c]
複製代碼

結構參數

function f3([x, t, ...z], ...w) {
  console.log(x, y, z, w)
}

f3([]);
f3([1, 2, 3, 4], 5, 6)
複製代碼

解構默認值 + 參數默認值 函數參數默認值若是是一個對象,而不是解構默認值。 它只在第二參數沒有傳入,或者傳入 undefined 的時候纔會生效。 看下面這個例子:

function test({ x = 1 } = {}, { y } = { y: 2 }) {
    console.log(x, y);
}
test({}, {}); //1 undefined
test(); // 1 2
test(undefined, undefined) //1 2
test({}, undefined) //1,2
test({ x: 2 }, { y: 3 }) //2 3
複製代碼

咱們傳入的參數({}), 因此沒有使用默認值 {y:10} ,而是在傳入的空對象 {} 上進行 {y} 結構

// 嵌套默認

//default合併進config
var defaultt = {
  options: {
    remove: 1,
    enable: 2,
  }
}

{
  //(帶默認值賦值的)的解構
  let {
    options: {
      remove: default.options.remove,
      enable: default.options.enable,
    } = {},
    log: {
      warn = defalut.log.warn,
      error = defalut.log.error
    }
  } = config;

  //重組
  config = {
    options: {
      remove,
      enable
    },
    log: {
      warn,
      error
    }
  };
}

//生成器
var o = {
  * foo() {
  }
}

//深刻理解
runSomething({
  something: function something(x, y) {
    if (x > y) {
      //交換x和y的遞歸調用
      return something(y, x)
    }
    return y - x
  }
})
複製代碼

第一個屬性 something 使得咱們可以經過 o.someting(..) 來調用,像是它的公開名稱。 而第二個 something 是一個詞法名稱, 用於其在自身內部引用這個函數,其目的是遞歸。

// 若是咱們採用簡潔方法的話
runSomething({
  something(x, y) {
    if (x > y) {
      //交換x和y的遞歸調用
      return something(y, x)
    }
    return y - x
  }
})
複製代碼

會提示找不到 someting 標識符,簡潔方法意味着匿名函數表達式。

你應該在不須要它們執行遞歸或者事件綁定/解綁定的時候使用

var o = {
  __id: 10,
  get id() {
    return this.__id++;
  },
  set id(v) {
    return this.__id = v;
  }
}
o.id;
o.id;
o.id = 20;
o.id;

o.__id;
o.__id;
複製代碼

setter 字面量必須有且只有一個聲明參數:省略或者多寫都是語法錯誤。

所需的參數可使用解構和默認值 set id({id: v=0}){..}

可是 gather/reset... 是不容許的 set id(...v){..}

super 只容許在簡潔方法中出現,而不容許在普通函數表達式屬性中出現,也只容許以 super.xxx 的形式(用於屬性/方法訪問)出現,而不能以 super() 的心事出現

字符串字面量在它出現的詞法做用域內, 沒有任何形式的動態做用域

function foo(string ,...value){
  console.log('string: ', string);
  console.log('...value: ', ...value);
}
var desc = 'awesome'

foo`Everything is ${desc}!`;
複製代碼

標籤(tag)部分,即..字符串字面量以前說的,是一個要調用的函數值。 實際上它能夠是任意結果爲函數的表達式,甚至能夠是一個結果爲另外一個函數的函數調用

箭頭函數

箭頭函數是 ES6 新增長的,下面咱們來介紹一下用法。

箭頭函數表達式的語法比函數表達式更簡潔,而且沒有本身的 this,arguments,super或 new.target。這些函數表達式更適用於那些原本須要匿名函數的地方,而且它們不能用做構造函數。

箭頭函數老是表達式,不存在箭頭函數聲明 在箭頭函數內部, this綁定不是都動態的,而是語法的。 => 是 var self = this( 或者.bind(this) )的詞法替代形式。

咱們說過箭頭函數從詞法範圍中獲取它們的值。這意味着它只是在周圍的代碼塊中使用這個值。它不在意叫它什麼,它只在意它在哪裏被定義。

let obj = {
  myVar: 'foo',
  
  myFunc: function() {
    console.log(this.myVar)  
  
    setTimeout(() => {
      console.log(this.myVar)
    }, 1000)
  }
}
obj.myFunc() // foo ... then... foo

複製代碼

myFunc 的 this 值取決於 obj ,所以,myFunc.myVar 可以成功從 foo 打印出來。然而,第二個函數被 setTimeout 調用,所以它的上下文不一樣。它的上下文其實是節點中的超時對象或瀏覽器中的窗口對象,因此儘管咱們可能依然想讓他指 向obj ,可是已經失去了綁定。

你可能但願 this 指向 obj。可是箭頭函數不會將它綁定到調用它們的對象。他們只是在定義的範圍內使用這個值。在這種狀況下,this 指向全局對象。因此箭頭函數不能用於對象方法!

let a = {
  foo: 1,
  bar: () => console.log(this.foo)
}

a.bar()  //undefined
複製代碼

箭頭函數的 this 並不指向 a 這個對象。 對象 a 並不能構成一個做用域,因此在往上到達全局做用域,this 就指向全局做用域。

構造方法

let Person = function(name, height) {
  this.name = name
  this.height = height
}
Person.prototype.hello = function() {
  console.log('Hi, my name is ' + this.name)
}
let alice = new Person('Alice', 1.7)
alice.hello() // Hi, my name is Alice

複製代碼

argument

let sum = (...args) => {
  return args.reduce((a, b) => a + b, 0)
}
sum(1, 4, 5) // 10

複製代碼

小技巧

省略{}和 return 若是箭頭函數體只包含一個表達式, 你能夠省略花括號 {} 和 return 關鍵字。不用擔憂省略 return,箭頭函數隱式返回表達式。

let funCon = who => `${who}, hello`
funCon('wyqn')

複製代碼

可能會遇到這種狀況, 想返回對象。

const funCon = who => ({ message: `${who}, hello!` });
funCon('wyqn'); // => { message: `wyqn, hello!` }
複製代碼

箭頭函數的適用時機規則:

  • 簡短單句,return 出某個值 -> 函數內部沒有 this 引用,且沒有自身引用(遞歸、事件綁定/解綁) -> 不執行函數表達式定義的其餘函數

  • 內層函數表達式,若是依賴於在包含它的函數中調用 var self = this( 或者.bind(this) ),那麼這個內層表達式可使用箭頭函數。

  • 底線 => 是關於 this、arguments、super 的詞法綁定。

箭頭函數不適用時機規則:

  • 不要在最外層定義箭頭函數,由於在函數內部操做 this 會很容易污染全局做用域。 最起碼在箭頭函數外部包一層普通函數,將 this 控制在可見的範圍內。

後記

歡迎關注微信公衆號!,進行更好的交流。
複製代碼

微信
相關文章
相關標籤/搜索