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原型。