国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ES6精華:函數擴展

lansheng228 / 1205人閱讀

摘要:在函數方面的擴展比較豐富也很實用,本篇概括了這中的精華知識。所以無法成為構造函數,不能使用操作符。參數將擴展運算符作用于參數,即為參數。聲明式,直接為函數名。通過構造函數生成的,為。函數的屬性,在其描述對象的屬性上,為函數名。

ES6在函數方面的擴展比較豐富也很實用,本篇概括了這中的精華知識。

1 箭頭函數

箭頭函數是ES6中定義函數的新形式。
新形式不僅簡化了定義方式,更為函數本身減重(其this, argumnets等與之前不同)。

let fn = () => {
  console.log("fn");
};
fn(); // "fn"

如果只有一個參數,可以省略括號。
(n => {
  console.log(n);
})(1); // 1

如果不帶 {} ,意味著直接返回 => 指向的目標。
console.log( (n => 2)(1) ); // 2
注意,指向的目標只能是單體,如果為表達式需要用 () 包裹形成單體。
console.log( (n => (n + 1))(1) ); // 2
1.1 this

箭頭函數沒有自己的this,其使用的this是引用外層的(類似閉包)。
因此其里面的this是固定的,在定義的那一刻起就已經確定,不會再變。

非嚴格模式下。

--- 之前的函數是執行時確定 this 。
window.id = 0;

let obj = { id: 1 };
let fn = function () {
  console.log(this.id);
};

fn(); // 0,引用的是 window 。
obj.fn = fn;
obj.fn(); // 1,引用的是 obj 。


--- 箭頭函數是定義時確定 this 。
window.id = 0;

let obj = { id: 1 };
let fn = () => {
  console.log(this.id);
};

fn();  // 0,引用的是 window 。
obj.fn = fn;
obj.fn(); // 0,引用的是 window 。

再利用多層箭頭函數來說明。
多層箭頭函數,this的尋找途徑是一層層向上查找的,類似作用域鏈查找。
所以多層箭頭函數在初次獲取到this時,全部函數的this便都確定了。

foo.call({id: 1})()(); // id: 1

function foo() {
  return () => {
    return () => {
      console.log("id:", this.id);
    };
  };
}

--- 等價于

function foo() {
  let _this = this;
  return function() {
    return function() {
      console.log("id:", _this.id);
    }
  }
}

因為沒有自身的this。
所以無法成為構造函數,不能使用new操作符。
所以不能用call, applybind這些方法改變this的指向。

let Person = () => {};
let p = new Person(); // 報錯,Person is not a constructor。

window.id = "000";
let fn = () => { console.log(this.id) };
let fn1 = fn.bind({ id: "111" });
fn1(); // "000"
1.2 其它的不同

函數體內沒有arguments對象,可以使用rest參數代替。
不能使用yield命令,因此箭頭函數不能用作Generator函數(可以使用async函數)。

let fn = (...args) => {
  console.log(args); // [1, 2]
  console.log(arguments); // 報錯,arguments is not defined。
};
fn(1, 2);
2 函數參數 2.1 默認值

可以為參數設定默認值。
當沒有傳遞該參數或值為undefined時,默認值將被使用。
借用此方式,可以簡化函數體,并使參數的性質、類型等更加清晰。

--- ES6 之前
function fn(id, conf) {
  id || requiredParam();
  conf = conf || {};
  
  conf.name = conf.name || "";
  conf.ago = conf.ago || 0;
  
  console.log(id, conf);
}

--- ES6 之后
function fn(
  id = requiredParam(),
  conf = {
    name: "",
    ago: 0
  }
) {
  console.log(id, conf);
}

function requiredParam() {
  throw Error("Missing parameter.");
}
2.2 解構賦值

結合解構賦值,默認值設定的功能會更為強大。
關于解構賦值,可參考此鏈接。
為了直觀的顯示它的優勢,我們將最終的結果分成三步。

1.使用解構賦值,快速聲明變量,并賦予相應的屬性值。

fn({
  id: "0003"
}); // 兩者都打印出:"0003" undefined

--- ES6 之前
function fn(conf) {
  let id = conf.id;
  let name = conf.name;
  console.log(id, name);
}

--- ES6 之后
function fn({id, name}) {
  console.log(id, name);
}


2.緊接著,為解構中的變量設定默認值。

fn({
  id: "0003"
}); // 兩者都打印出:"0003" "Unnamed"

--- ES6 之前
function fn(conf) {
  let id = conf.id || "0000";
  let name = conf.name || "Unnamed";
  console.log(id, name);
}

--- ES6 之后
function fn({
  id = "0000",
  name = "Unnamed"
}) {
  console.log(id, name);
}


3.最后,再為此參數設定默認值。

fn(); // 兩者都打印出:"0000" "Unnamed"

--- ES6 之前
function fn(conf) {
  conf = conf || {
    id: "0000",
    name: "Unnamed"
  };
  
  let id = conf.id;
  let name = conf.name;
  
  console.log(id, name);
}

--- ES6 之后
function fn({
  id = "0000",
  name = "Unnamed"
} = {}) {
  console.log(id, name);
}

再思考一個問題:是在解構中還是在參數默認值中設定屬性的值?

function fn1(x = {}, {a = 1, b = 2} = x) { console.log(a, b, x) }
function fn2(x = {a: 1, b: 2}, {a, b} = x) { console.log(a, b, x) }

這兩方法的區別在于:變量a, b的默認值的設置地點。
如果要優先確保解析后的變量有默認值,第一種方式更為有效。

fn1(); // 1 2 {}
fn2(); // 1 2 {a:1, b:2}

fn1({}); // 1 2 {}
fn2({}); // undefined undefined {}

fn1({ a: 0 }); // 0 2 {a:0}
fn2({ a: 0 }); // 0 undefined {a:0}
2.3 rest 參數

將擴展運算符作用于參數,即為rest參數。
它會將所有相應的傳入參數合并成一個數組,賦值給rest參數。
rest參數只能是最后一個參數,沒有正則中所謂的貪婪性,否則會報錯。

打印出:"0001" ["m1","m2"]。

fn("0001", "m1", "m2");

function fn(groupId, ...members) {
  console.log(groupId, members);
}
2.4 作用域

如果函數參數使用了默認值、解構賦值或擴展運算符,就產生了參數作用域。

執行函數體時,會先默認聲明參數變量。
如果存在參數作用域,會先執行它,再到函數體作用域中。
初始化結束后,參數作用域消失,之后函數體會默認聲明同名變量指向相應的參數變量。

因為作用域的存在,參數是惰性(調用時)求值的。

let n = 0;

fn(); // 1

n = 1;
fn(); // 2

function fn(num = (n + 1)) {
  console.log(num);  
}

因為默認聲明原則,在函數體中聲明同名參數相當二次聲明。
使用let, const相當重復聲明,會報錯。
使用var會解綁函數體與參數作用域的關聯,變量便成了純粹的函數體變量。

--- 普通
let x = 0;
fn(1); // 2
function fn(x, y = () => { console.log(x) }) {
  x = 2;
  y();
}

--- 解綁
let x = 0;
fn(1); // 1
function fn(x, y = () => { console.log(x) }) {
  var x = 2;
  y();
}

如果存在參數作用域,就不能在函數體中顯式的設定嚴格模式,否則報錯。
因為函數內部的嚴格模式,應該同時作用于函數體和參數作用域。
但是只有進入函數體,才能知道是否有顯式地聲明,而參數體卻先于函數體執行。
不過可以變通的,將此函數置于一個處在嚴格模式的環境中。

報錯:Illegal "use strict" directive ...
function fn(n = 0) {
  "use strict";
}
3 函數屬性 3.1 name

不同形式的函數,其name屬性值構建的方式也不相同,下面是個人總結的八種方式。

1.聲明式,直接為函數名。
console.log(fn.name); // "fn"
function fn() {}

2.命名函數表達式,直接為函數名。
let fn1 = function fn() {};
console.log(fn1.name); // "fn"

3.表達式,為第一次賦值的變量/屬性。
let fn = function() {};
console.log(fn.name); // "fn"
let fn1 = fn();
console.log(fn.name); // "fn"
let obj = { fn: function() {} };
console.log(fn.name); // "fn"

4.沒有賦值的匿名表達式,為空。
console.log( (function() {}).name ); // ""

5.通過構造函數生成的,為 anonymous 。
console.log( (new Function()).name ); // "anonymous"

6.通過 bind() 生成的,name 屬性值會加上 bound 前綴。
console.log( (function() {}).bind({}).name ); // "bound "
console.log( (function fn() {}).bind({}).name ); // "bound fn"

7.如果對象的方法名為 Symbol 值,name 屬性返回的是此 Symbol 的描述。
let s1 = Symbol();
let s2 = Symbol("s2");
console.log( ({ [s1]() {} })[s1].name ); // ""
console.log( ({ [s2]() {} })[s2].name ); // [s2]

8.getter/setter 函數的 name 屬性,在其描述對象的 get/set 屬性上,為 get/set 函數名。
let obj = {
   get name() {}
};
Object.getOwnPropertyDescriptor(obj, "name").get.name; // "get name"
3.2 length

其本質含義是該函數預期傳入的參數個數。
如果參數有默認值或為rest參數,則它以及它之后的參數都不會被計算在內。
基于這點,在參數設計上,一般把可以省略或有默認值的參數設置為尾參數。

console.log( (function(...args) {}).length ); // 0
console.log( (function(a, , c = 5, d) {}).length ); // 2
3.3 arguments

類數組對象arguments保存的僅僅存儲調用方法時傳進來的參數。
這意味著,使用默認值的參數、解構參數或rest參數等都不在其中。

(function (name = "Wmaker") {
  console.log(name, arguments.length);
})(); // "Wmaker" 0

(function ({a, b}) {
  console.log(a, b, arguments.length);
})({ a: 1, b: 2 }); // 1 2 1

(function (...arr) {
  console.log(arr, arguments.length);
})(1, 2, 3); // [1, 2, 3] 3

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95599.html

相關文章

  • ES6精華:正則擴展

    摘要:本篇概括了中正則表達式新增部分的精華要點最好有的基礎。標志使正則處于模式。關于的字符擴展知識,可查看這里。四字節字符處于模式下的正則,可以正確識別位四字節字符。 本篇概括了ES6中正則表達式新增部分的精華要點(最好有ES5的基礎)。 1 u 標志 使正則處于Unicode模式。 關于ES6的字符擴展知識,可查看這里。 1.1 四字節字符 處于Unicode模式下的正則,可以正確識別3...

    paulli3 評論0 收藏0
  • ES6精華:字符串擴展

    摘要:四字節字符大幅增強了對字節位字符的支持。內部使用編碼規則網頁通常為。字符固定為字節,字節為位二進制,其碼點小于。有些符號的碼點大于,需字節表示,即常說的位字符。表示方法新增一種表示字符的方法。用將碼點括起,使其可直接表示超過的值。 1 四字節字符 ES6大幅增強了對4字節(32位)字符的支持。 JS內部使用UTF-16編碼規則(網頁通常為UTF-8)。 1字符固定為2字節,1字節為...

    Jiavan 評論0 收藏0
  • ES6精華:數值擴展

    摘要:基礎極值采用標準的位雙精度格式存儲數值。如果數值的精度超過此限度,第位及后面的會被丟棄。數值的極值分為兩種可表示的極值和可精確計算的極值浮點型不算。超過精度的數值可正確顯示,但由其計算得出的結果可能不準確。整型數值安全區間。 ES6為數值增加了些常量和方法,使計算更為簡便安全。本篇概括了這中的精華知識。 1 基礎 1.1 極值 JS采用IEEE 754標準的64位雙精度格式存儲數值。 ...

    newtrek 評論0 收藏0
  • ES6精華:Let & Const

    摘要:所以,最終極的辦法是一層一層凍結所有對象。塊級作用域使呈現出塊級作用域的特征。聲明的變量僅存在于當前塊級作用域中。在中,嚴格模式下等價于使用聲明,非嚴格下等價于使用。在中使用聲明的變量,為了保持程序的嚴謹性,不允許被訪問。 let和const都是聲明變量的新方式。 一般的,由于這兩種聲明方式的特性,現在項目組的開發規范中都會要求:不使用var而是let或const。 Const co...

    UnixAgain 評論0 收藏0
  • ES6精華:解構賦值

    摘要:按一定的匹配模式,從數組或對象中解構出相應值,并賦值給變量。和是單值,沒有相應的構造函數,不能被解構。等價于報錯解構方式左側的解構符決定如何看待右側的解構值。解構符意味著視右側的值為對象,采用對象解構。 按一定的匹配模式,從數組或對象中解構出相應值,并賦值給變量。 let [a] = [3]; // a = 3 let [, a] = [3, [7]]; // a = [7] let ...

    468122151 評論0 收藏0

發表評論

0條評論

lansheng228

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<