摘要:在函數方面的擴展比較豐富也很實用,本篇概括了這中的精華知識。所以無法成為構造函數,不能使用操作符。參數將擴展運算符作用于參數,即為參數。聲明式,直接為函數名。通過構造函數生成的,為。函數的屬性,在其描述對象的屬性上,為函數名。
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) ); // 21.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, apply和bind這些方法改變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 ); // 23.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中正則表達式新增部分的精華要點(最好有ES5的基礎)。 1 u 標志 使正則處于Unicode模式。 關于ES6的字符擴展知識,可查看這里。 1.1 四字節字符 處于Unicode模式下的正則,可以正確識別3...
摘要:四字節字符大幅增強了對字節位字符的支持。內部使用編碼規則網頁通常為。字符固定為字節,字節為位二進制,其碼點小于。有些符號的碼點大于,需字節表示,即常說的位字符。表示方法新增一種表示字符的方法。用將碼點括起,使其可直接表示超過的值。 1 四字節字符 ES6大幅增強了對4字節(32位)字符的支持。 JS內部使用UTF-16編碼規則(網頁通常為UTF-8)。 1字符固定為2字節,1字節為...
摘要:基礎極值采用標準的位雙精度格式存儲數值。如果數值的精度超過此限度,第位及后面的會被丟棄。數值的極值分為兩種可表示的極值和可精確計算的極值浮點型不算。超過精度的數值可正確顯示,但由其計算得出的結果可能不準確。整型數值安全區間。 ES6為數值增加了些常量和方法,使計算更為簡便安全。本篇概括了這中的精華知識。 1 基礎 1.1 極值 JS采用IEEE 754標準的64位雙精度格式存儲數值。 ...
摘要:所以,最終極的辦法是一層一層凍結所有對象。塊級作用域使呈現出塊級作用域的特征。聲明的變量僅存在于當前塊級作用域中。在中,嚴格模式下等價于使用聲明,非嚴格下等價于使用。在中使用聲明的變量,為了保持程序的嚴謹性,不允許被訪問。 let和const都是聲明變量的新方式。 一般的,由于這兩種聲明方式的特性,現在項目組的開發規范中都會要求:不使用var而是let或const。 Const co...
摘要:按一定的匹配模式,從數組或對象中解構出相應值,并賦值給變量。和是單值,沒有相應的構造函數,不能被解構。等價于報錯解構方式左側的解構符決定如何看待右側的解構值。解構符意味著視右側的值為對象,采用對象解構。 按一定的匹配模式,從數組或對象中解構出相應值,并賦值給變量。 let [a] = [3]; // a = 3 let [, a] = [3, [7]]; // a = [7] let ...
閱讀 1750·2021-09-26 09:46
閱讀 3029·2021-09-22 15:55
閱讀 2617·2019-08-30 14:17
閱讀 3033·2019-08-26 11:59
閱讀 1817·2019-08-26 11:35
閱讀 3162·2019-08-26 10:45
閱讀 3159·2019-08-23 18:28
閱讀 1136·2019-08-23 18:21