jsjavascript
Ref: 模板字符串php
策略:${var},放在反引號中!html
經過tag來表示字符串。java
使用for輸出完整的字符串,記得最後一個strings[strings.length-1]。git
c#es6
Ref: 一個很是好的C#字符串操做處理類StringHelper.csgithub
Ref: 字符串(C# 編程指南)正則表達式
Ref: 經常使用C#字符串函數大全express
js編程
修飾符:
^
和結束標識符$
的使用。var urlReg = /(\w+):\/\/([\w.]+)\/(\S*)/; var myHomepage = "http://www.wanjilong.com/homepage"; var result = myHomepage.match(urlReg);
console.log(result); for (var i = 0, len = result.length; i < len; ++i) { console.log(i, result[i]); }
Ref: JavaScript 正則表達式
Ref: JavaScript RegExp 對象
var patt = new RegExp(pattern,modifiers); 或者,更簡單的方法 var patt = /pattern/modifiers;
test():一個字符串是否匹配某個模式
exec():檢索字符串中的正則表達式的匹配
Method | Description |
---|---|
exec |
A RegExp method that executes a search for a match in a string. It returns an array of information or null on a mismatch. |
test |
A RegExp method that tests for a match in a string. It returns true or false. |
match |
A String method that executes a search for a match in a string. It returns an array of information or null on a mismatch. |
search |
A String method that tests for a match in a string. It returns the index of the match, or -1 if the search fails. |
replace |
A String method that executes a search for a match in a string, and replaces the matched substring with a replacement substring. |
split |
A String method that uses a regular expression or a fixed string to break a string into an array of substrings. |
c#
Ref: C# 正則表達式
匹配:匹配了以 'm' 開頭以 'e' 結尾的單詞
using System; using System.Text.RegularExpressions; namespace RegExApplication { class Program { private static void showMatch(string text, string expr) { Console.WriteLine("The Expression: " + expr); MatchCollection mc = Regex.Matches(text, expr); foreach (Match m in mc) { Console.WriteLine(m); } } static void Main(string[] args) { string str = "make maze and manage to measure it"; Console.WriteLine("Matching words start with 'm' and ends with 'e':"); showMatch(str, @"\bm\S*e\b"); Console.ReadKey(); } } }
替換:替換掉多餘的空格
using System; using System.Text.RegularExpressions; namespace RegExApplication { class Program { static void Main(string[] args) { string input = "Hello World "; string pattern = "\\s+"; string replacement = " "; Regex rgx = new Regex(pattern); string result = rgx.Replace(input, replacement); Console.WriteLine("Original String: {0}", input); Console.WriteLine("Replacement String: {0}", result); Console.ReadKey(); } } }
js
Number.EPSILON
其實是 JavaScript 可以表示的最小精度】
c#
Ref: C#數學計算包 Math.NET
Ref: Math Class【MSDN】
js
(function (a) {}).length // 1 (function (a = 5) {}).length // 0 (function (a, b, c = 5) {}).length // 2
指定了默認值後,length
屬性將失真。
後文的 rest 參數也不會計入length
屬性
(function(...args) {}).length // 0
/**
* 只計算最後一個有默認值參數以前的」未默認初始化「的參數的個數
*/ (function (a = 0, b, c) {}).length // 0 (function (a, b = 1, c) {}).length // 1
例一:
let x = 1; function f(y = x) { # 調用函數時,參數造成一個單獨的做用域 let x = 2; # 這一條語句 其實沒用 console.log(y); } f() // 1f
注意:參數中默認爲是let,故鎖住了做用域。
例二:
let foo = 'outer'; function bar( func = () => foo ) { // 同理,foo是外層的 let foo = 'inner'; console.log(func()); } bar(); // outer
例三:這裏是三個做用域的x。
var x = 1;
function foo( x, y = function() { x = 2; } ) { // 參數中的x是單獨的做用域 var x = 3; // 函數內部的x是另外一個做用域 y(); // 執行後,內部變量和外部全局變量的值都沒變 console.log(x); } foo() // 3 x // 1yxx
這裏,只有兩個做用域,函數參數和函數內部的做用域是同樣的。
var x = 1; function foo(x, y = function() { x = 2; }) { x = 3; // 內部變量就指向第一個參數 y(); console.log(x); } foo() // 2 x // 1xx
至關棒的tricky的方法:利用參數默認值,能夠指定某一個參數不得省略,若是省略就拋出一個錯誤。
一個不能夠省略的參數:
一個能夠省略的參數:
function foo(optional = undefined) { ··· }
比過去的argument要好
// arguments變量的寫法 function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); }
對象不是數組,而是一個相似數組的對象。
// 因此爲了使用數組的方法,必須使用先將其轉爲數組。
----------------------------------------------------------------------- // rest參數的寫法 const sortNumbers = (...numbers) => numbers.sort();
// rest 參數就不存在這個問題,它就是一個真正的數組,數組特有的方法均可以使用。// argumentsArray.prototype.slice.call
rest 參數必須在尾部
rest 參數以後不能再有其餘參數(即只能是最後一個參數),不然會報錯。
// 數組參數的典型用法
function push(array, ...items) { items.forEach(function(item) { array.push(item); console.log(item); }); } var a = []; push(a, 1, 2, 3)
只要參數使用了默認值、解構賦值、或者擴展運算符,就不能顯式指定嚴格模式。
產生了矛盾點:"只有從函數體之中,才能知道參數是否應該以嚴格模式執行,可是參數卻應該先於函數體執行"。
// 報錯 function doSomething(value = 070) { 'use strict'; # 在執行這裏前,如何處理參數是個問題 return value; }
那乾脆禁止掉就行了!
但並非說,這跟‘嚴格模式’的初衷有衝突,兩種方法能夠規避這種限制。
第一種,是設定全局性的嚴格模式,這是合法的。
'use strict'; function doSomething(a, b = a) { // code }
第二種,是把函數包在一個無參數的當即執行函數裏面。
const doSomething = (function () { 'use strict'; return function(value = 42) { return value; }; }());
參考:[JS] Why "strict mode" here
const bar = function baz() {}; // ES5 bar.name // "baz" // ES6 bar.name // "baz"
其餘狀況見原文。
一樣的,注意大括號(代碼塊) 是否做爲了返回值。
// 報錯 let getTempItem = id => { id: id, name: "Temp" }; // 不報錯 let getTempItem = id => ({ id: id, name: "Temp" });
// 雖然能夠運行,但會獲得錯誤的結果
// 因爲引擎認爲大括號是代碼塊,因此執行了一行語句a: 1
// 這時,a
能夠被解釋爲語句的標籤,所以實際執行的語句是1;
// 而後函數就結束了,沒有返回值。
let foo = () => { a: 1 };
a: 1a1;foo() // undefined
// 若是箭頭函數只有一行語句,且不須要返回值,能夠採用下面的寫法,
// 就不用寫大括號了
let fn = () => void doesNotReturn();
便捷一:箭頭函數能夠與變量解構結合使用。
const full = ({ first, last }) => first + ' ' + last;
// 等同於 function full(person) { return person.first + ' ' + person.last; }
便捷二:簡化回調函數。
// 正常函數寫法 [1,2,3].map(function (x) { return x * x; }); // 箭頭函數寫法 [1,2,3].map(x => x * x);
便捷三:與 rest 參數相結合。
const numbers = (...nums) => nums; numbers(1, 2, 3, 4, 5) // [1,2,3,4,5]
const headAndTail = (head, ...tail) => [head, tail]; headAndTail(1, 2, 3, 4, 5) // [1,[2,3,4,5]]
箭頭函數的使用注意點
(1)函數體內的this
對象,就是定義時所在的對象,而不是使用時所在的對象。
this
對象的指向是可變的;
可是在箭頭函數中,它是固定的。
做用一
例子一:
function foo() { setTimeout( () => { console.log('id:', this.id); }, 100 ); } var id = 21; // 對象{id:42}做爲了參數 foo.call({ id: 42 }); // id: 42
例子二:
Timer
函數內部設置了兩個定時器,分別使用了箭頭函數和普通函數。
前者的this
綁定定義時所在的做用域(即Timer
函數),
後者的this
指向運行時所在的做用域(即全局對象)。
因此,3100 毫秒以後,timer.s1
被更新了 3 次,而timer.s2
一次都沒更新。
做用二
箭頭函數可讓this
指向固定化,這種特性頗有利於封裝回調函數。
注意:
this
指向的固定化,並非由於箭頭函數內部有綁定this
的機制,實際緣由是箭頭函數根本沒有本身的this
,
致使內部的this
就是外層代碼塊的this。
除了this
,如下三個變量在箭頭函數之中也是不存在的,指向外層函數的對應變量:arguments
、super
、new.target
。
// ES6 function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } // ES5 function foo() { var _this = this; setTimeout(function () { console.log('id:', _this.id); }, 100); }
請問下面的代碼之中有幾個this
?
(2)不能夠看成構造函數,也就是說,不可使用new
命令,不然會拋出一個錯誤。
(3)能夠用 rest 參數,但不可使用arguments
對象,該對象在函數體內不存在。
(4)不可使用yield
命令,所以箭頭函數不能用做 Generator 函數。
以下,可見箭頭函數帶來的好處,有點builder or pipeline的感受。
function insert(value) { return { into: function (array) { return { after: function (afterValue) { array.splice(array.indexOf(afterValue) + 1, 0, value); return array; }}; }}; } insert(2).into([1, 3]).after(1); //[1, 2, 3]
上面這個函數,可使用箭頭函數改寫。【記得加圓括號】
可讀性提高,也能夠採用下面的寫法
const plus1 = a => a + 1; const mult2 = a => a * 2; mult2(plus1(5)) // 12
箭頭函數還有一個功能,就是能夠很方便地改寫 λ 演算。
【λ 演算】就是一種特殊的語法所書寫的匿名函數。
參見:神奇的λ演算
在原生js中會有三個很常見的函數,call, apply, bind。他們的做用就是改變當前函數的this指針。
-- 理論 --
當一個object沒有某個方法,可是其餘的有,咱們能夠藉助call或apply用其它對象的方法來操做!
另一個對象whiteDog = {food:"bone"},
咱們不想對它從新定義say方法,咱們能夠經過call或apply用blackCat的say方法:blackCat.say.call(whiteDog)。
此時,say:function()中的this指針就成了whiteDog,this.food就變成了「bone」。
-- 實戰 --
var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
箭頭函數能夠綁定this
對象,大大減小了顯式綁定this
對象的寫法(call
、apply
、bind
)。
可是,箭頭函數並不適用於全部場合,因此如今有一個提案,提出了「函數綁定」(function bind)運算符,用來取代call
、apply
、bind
調用。
【提案暫時不看】
尾調用(Tail Call)是函數式編程的一個重要概念,自己很是簡單,一句話就能說清楚,就是指某個函數的最後一步是調用另外一個函數。
function f(x) { if (x > 0) { return m(x) } return n(x); }
"尾調用"因爲是函數的最後一步操做,因此不須要保留外層函數的調用幀,由於調用位置、內部變量等信息都不會再用到了,只要直接用內層函數的調用幀,取代外層函數的調用幀就能夠了。
大大節省內存!
function f() { let m = 1; let n = 2; return g(m + n); } f(); // 等同於 function f() { return g(3); } f(); // 等同於 g(3);
反例子:
function addOne(a){ var one = 1; function inner(b){ return b + one; // 由於這裏,因此被迫在調用inner時還須要保留住var one,也就不是tail call了 } return inner(a); }
NB: ES6 的尾調用優化只在嚴格模式下開啓,正常模式是無效的。
這是由於在正常模式下,函數內部有兩個變量,能夠跟蹤函數的調用棧。
func.arguments
:返回調用時函數的參數。func.caller
:返回調用當前函數的那個函數。
對於尾遞歸來講,因爲只存在一個調用幀,因此永遠不會發生「棧溢出」錯誤。
function factorial(n) { if (n === 1) return 1; return n * factorial(n - 1); } factorial(5) // 120
--------------------------------------------------
改寫成尾遞歸,只保留一個調用記錄,複雜度由O(n) --> O(1) 。
function factorial(n, total) { if (n === 1) return total; return factorial(n - 1, n * total); } factorial(5, 1) // 120
可見,訣竅就在於:把全部用到的內部變量改寫成函數的參數。
還有就是:只須要知道循環能夠用遞歸代替,而一旦使用遞歸,就最好使用尾遞歸。
其餘部分,柯里化(currying)【將多參數的函數轉換成單參數的形式】詳見連接。
尾遞歸優化只在嚴格模式下生效。
在正常模式下,或者那些不支持該功能的環境中,就是本身實現尾遞歸優化。
減小調用棧?就是採用「循環」換掉「遞歸」。
詳見原連接。
ES2017 容許函數的最後一個參數有尾逗號(trailing comma)。
這樣的規定也使得,函數參數與數組和對象的尾逗號規則,保持一致了。
基本值類型不是對象(number、string、Boolean、Undefined);
剩下的引用類型(函數、數組、null...)都是對象。
對象是經過函數建立的,而函數又是一種對象。那麼這是爲何呢?這就牽扯到prototype原型。