var a = new String('abc'); var b = new String('abc'); console.log(a == b) // false console.log(a === b) // false
Boolean(new Boolean(false)) // true Number(new Number(123)) // 123 String(new String('abc')) // abc new Boolean(new Boolean(false)) // true对象
做用: 经过指定边界(separator)将字符串分割成子字符串,返回字符串组成的数组。javascript
separator: 可选,能够为字符串或正则表达式。不传的话,将原字符串封装在数组中返回html
limit: 可选, 若传入,最多返回数组中limit个子字符串java
注:若separator为包含子表达式分组的正则表达式,子表达式匹配的字符串也会做为数组中的元素返回。正则表达式
'a, b , '.split(/(,)/) # ['a', ',', ' b ', ',', ' ']
做用: 捕获分组或返回全部匹配的子字符串算法
注: 若regexp未设置全局标志/g, 则返回一个对象(数组: 存在index和input属性),存放第一次匹配相关的信息;若设置了/g标志,则将全部匹配的子字符串(不包含分组元素)放在一个数组中返回; 若是未匹配到任何子字符串,返回null跨域
var a = '-abb--aaab'.match(/(a+)b/) // ["ab", "a"] a.index === 1 // true a.input === '-abb--aaab' // true var b = '-abb--aaab'.match(/(a+)b/g) // ["ab", "aaab"] b.index === undefined // true b.input === undefined // true var c = '-abb--aaab'.match(/(a+)bc/g) // null c === null // true
存在两个参数: search, replacement数组
search: 字符串或者正则表达式。浏览器
1) 字符串: 在字符串中找到匹配的字面量,只能替换一次出现的匹配项,暂不存在 (replaceAll函数),想要替换屡次出现的匹配项,必须使用正则表达式/g标识。 2) 正则表达式: 对输入的字符串进行匹配。若是想替换屡次,必须使用/g标识
replacement: 字符串或者函数。安全
1) 字符串: 描述如何替换找到的匹配项), 使用该字符串替换匹配项,替换字符串中的$ 符号容许使用彻底匹配或者匹配分组进行替换 2) 函数: 执行替换并提供参数匹配信息.
'iixxxixx'.replace('i', 'o') // oixxxixx 'iixxxixx'.replace(/i/, 'o') // oixxxixx 'iixxxixx'.replace(/i/g, 'o') // ooxxxoxx // 使用$符号 'iixxxixx'.replace(/i+/g, '($&)') // (ii)xxx(i)xx 'iixxxixx'.replace(/(i+)/g, '($1)') // (ii)xxx(i)xx // 使用函数替换 function repl(search, group, offset, input) { return '{ search: ' + search.toUpperCase() + ', group: ' + group + ', offset: ' + offset + ' }'; } 'iixxxixx'.replace(/(i+)/g, repl) // { search: II, group: ii, offset: 0 }xxx{ search: I, group: i, offset: 5 }xx
内容用来逐字替换匹配项,惟一例外是特殊字符美圆符号($),它会启动替换指令
app
分组:$n在匹配中插入分组n。n必须大于等于1($0没有任何特殊含义)
匹配的子字符串:
1) $\` (反引号)插入匹配项以前的文本 2) $& 插入完整的匹配项 3) $' (单引号)插入匹配项以后的文本
$$ 插入单个$字符
'axb cxd'.replace(/x/g, "($`,$&,$')"); // a(a,x,b cxd)b c(axb c,x,d)d '"foo" and "bar"'.replace(/"(.*?)"/g, '#$1#'); // #foo# and #bar#
若是replacement为函数,它须要对替换匹配项的字符串进行处理。签名以下:
function replacement (search, group_1, ..., group_n, offset, input){}
search与前面介绍的$&(完整的匹配项)相同, offset表示找到匹配项的位置,input是正在被匹配的字符串
search: 正则表达式匹配到的字符串
group: 若是存在分组,该值为匹配到的分组值, 可变参数, 匹配到分组有多少个,这个参数就有多少个, 若是不存在,表示匹配到子字符所在原字符串的位置
offset(倒数第二个参数): 匹配到子字符所在原字符串的位置
input(最后一个参数): 原字符串
function replaceFunc (match) { return 2 * match; } '3 peoples and 5 oranges'.replace(/\d+/g, replaceFunc); // 6 peoples and 10 oranges
function isObject (value) { return value === Object(value); }
forEach函数存在两个参数,第一个是回调函数,第二个参数为第一个参数(回调函数)提供this
var obj = { name: 'Jane', friends: ['Tarzan', 'Cheeta'], loop: function () { 'use strict'; this.friends.forEach(function (friend) { console.log(this.name + ' knows ' + friend); }, this) } }
使用方法: Object.create(proto, properties?)
参数:
proto: 新建立对象的原型
properties: 可选,经过描述符给新建立对象添加属性
var PersonProto = { describe: function () { return 'Person named ' + this.name; } } var jane = Object.create(PersonProto, { name: { value: 'Jane', writable: true, configurable: true, enumerable: true } }); jane.describe() // 'Person named Jane'
调用方法: Object.getPrototypeOf(obj)
Object.getPrototypeOf(jane) === PersonProto // true
语法: Object.prototype.isPrototypeOf(obj)
检查接受者是不是obj的原型(直接或者间接)
var A = {}; var B = Object.create(A); var C = Object.create(B); A.isPrototypeOf(C); // true PersonProto.isPrototypeOf(jane); // true
遍历对象obj的原型链, 返回键为propKey的自定义属性的第一个对象
function getDefiningObject(obj, propKey) { while (obj && !Object.prototype.hasOwnProperty.call(obj, propKey)) { obj = Object.getPrototypeOf(obj); } return obj; }
能够列吃全部自有属性,也能够列出可枚举属性
1) Object.getOwnPropertyNames(obj) 返回obj的全部自有属性键 2) Object.key(obj) 返回obj全部可枚举的自有属性键
Object.defineProperty(obj, propKey, propDesc)
建立或改变obj对象的propKey键的属性,并经过propDesc制定这个属性的特性,返回修改后的对象
Object.getOwnPropertyDescriptor(obj, PropKey)
返回obj对象的propKey键自有(非继承)属性描述符,若是没有该属性,则返回undefined.
需求:
1) 就有相同的原型 2) 具备相同的属性及属性特性
function copyObject (orig) { // 1. copy has same prototype as orig var copy = Object.create(Object.getPrototypeOf(orig)); // 2. copy ass orig's own properties function copyOwnPropertiesFromObjct (target, source) { var ownProperties = Object.getOwnPropertyNames(source); for (var property of ownProperties) { var sourcePropertyDescriptor = Object.getOwnPropertyDescriptor(source, property); Object.defineProperty(target, property, sourcePropertyDescriptor); } } copyOwnPropertiesFromObjct(copy, orig); return copy; }
若是一个对象obj从原型继承了不可写的属性foo, 在严格模式下,那么不能给obj.foo赋值。
var proto = Object.create({}, { foo : { value: 'a', writable: false } }); // var proto = Object.defineProperty({}, 'foo', { value: 'a', writable: false }); var obj = Object.create(proto); obj.foo = 'b'; // b obj.foo // a // IIFE (function () { 'use strict'; obj.foo = 'b' }()); // Uncaught TypeError: Cannot assign to read only property 'foo' of object '#<Object>'
这符合赋值改变但不破坏继承属性的理念。若是一个继承属性是只读的,应该禁止全部修改操做
1) for-in // 循环全部可枚举属性(自有+继承) 2) Object.keys() // 列出全部自有可枚举属性 2) JSON.stringify() // 全部自有可枚举属性
不能添加属性,能够删除属性, 能够修改已有自有属性
var obj = { foo: 'a' }; Object.preventExtensions(obj); obj.bar = 'b'; // 宽松模式下,添加失败 obj.bar // undefined (function () { 'use strict'; obj.bar = 'b' }()) // 严格模式下,抛出异常 // Uncaught TypeError: Can't add property bar, object is not extensible // 删除属性 delete obj.foo; // a obj.foo // undefined
判断某个对象是否能够扩展: Object.isExtensible(obj)
Object.isExtensible(obj); // false Object.isExtensible({}); // true
注: 防止扩展时,返回false
不能添加属性,且不能删除属性, 只能修改已有自有属性。
(封闭 === 防止扩展 + 不能删除属性)
var obj = { foo: 'a' } Object.getOwnPropertyDescriptor(obj, 'foo'); // before sealing // {value: "a", writable: true, enumerable: true, configurable: true} Object.seal(obj); Object.getOwnPropertyDescriptor(obj, 'foo'); // after sealing // {value: "a", writable: true, enumerable: true, configurable: false} // 不能改变其属性特性 Object.defineProperty(obj, 'foo', { enumerable: false }); // Uncaught TypeError: Cannot redefine property: foo
判断一个对象是否封闭: Object.isSealed(obj)
Object.isSealed(obj); // true Object.isSealed({}); // false
注: 对象封闭时,返回true
不能添加属性,不能删除属性, 同时也修改已有自有属性。
(冻结 === 封闭 + 不能修改属性)
var point = { x: 17, y: -5 }; Object.freeze(point); // 赋值操做,宽松模式下,执行失败;严格模式下,抛出异常。 point.x = 6 point.x // 17 (function () { 'use strict'; point.x = 2; }()); // Uncaught TypeError: Cannot assign to read only property 'x' of object '#<Object>' (function () { 'use strict'; point.z = 62; }()); // Uncaught TypeError: Can't add property z, object is not extensible (function () { 'use strict'; delete point.x; }()); // Uncaught TypeError: Cannot delete property 'x' of #<Object>
判断一个对象是否被冻结: Object.isFrozen(obj)
Object.isFrozen(obj); // true Object.isFrozen({}); // false
注: 对象被冻结时,返回true
全部保护对象的方法,只能保护基本类型的自有属性,对于对象不起做用(能够改变属性值为对象中对象的属性)
var obj = { foo: 1, bar: [1, 2, 3], cer: { a: '123' } }; Object.freeze(obj); obj.foo = 2; // no effect obj.foo // 1 obj.bar.push('bar'); // 4: changes obj.bar obj.bar // [1, 2, 3, "bar"] obj.cer.b = 'cer'; //cer: changes obj.cer obj.cer // {a: "123", b: "cer"}
几乎全部的对象都是Object的实例,由于Object.prototype在这些对象的原型链上,但也有对象不属于这种状况。
Object.create(null) instanceof Object // false Object.prototype instanceof Object // false Object.getPrototypeOf(Object.create(null)) // null Object.getPrototypeOf(Object.prototype) // null
这类对象位于原型链的末端,但typeof能够正确的把这些对象归类为对象:
typeof Object.create(null) // object typeof Object.prototype // object
在Web浏览器中,每个帧和窗口都拥有本身的域,具备独立的全局变量。这使得instanceof不可用于那些跨域的对象。
若是myvar是来自另外一个域的数组,那么它的原型是那个域的Array.prototype。在当前域中,使用instanceof检测的是否为myvar的原型链上是否存在当前域的Array.prototype, 会返回false。
可使用ECMAScript 5的函数Array.isArray()来判断是否为数组
<!DOCTYPE html> <html> <head> <title>Test</title> </head> <script type="text/javascript"> function test (myvar) { var iframe = window.frames[0]; console.log(myvar instanceof Array); // false console.log(myvar instanceof iframe.Array); // true console.log(Array.isArray(myvar)); // true } </script> <body> <iframe srcdoc="<script type='text/javascript'>window.parent.test([])</script>"></iframe> </body> </html>
var jane = { name: 'Jane', 'not an indentifier': 123, describe: function () { return 'Person named ' + this.name; } } jane.describe() // Person named Jane
obj.propKey // 访问 obj.propKey = value // 赋值 delete obj.propKey // 删除
obj['propKey'] // 访问 obj['propKey'] = value // 赋值 delete obj['propKey'] // 删除
Object.create(proto, propDescObj?) // 建立指定原型的对象 Object.getPrototypeOf(obj) // 获取原型
Object.keys(obj) Object.getOwnPropertyNames(obj) for (var propKey in obj) Object.prototype.hasOwnProperty.call(obj, propkey)
// 定义 Object.defineProperty(obj, propKey, propDesc) Object.defineProperties(obj, propDescObj) Object.create(obj, propDescObj) // 获取 Object.getOwnPropertyDescriptor(obj, propKey)
// 防止扩展: 不能添加属性,能删除属性或修改属性值 Object.preventExtensions(obj) Object.isExtensible(obj) // 封装: 不能添加或者删除属性,能修改属性值 Object.seal(obj) Object.isSealled(obj) // 冻结: 不能添加或者删除属性,也不能修改属性值 Object.freeze(obj) Object.isFrozen(obj)
// 将对象转换为基本类型的值 Object.prototype.toString() Object.prototype.valueOf() // 返回本地语言环境的表明对象的字符串 Object.prototype.toLocalString() // 原型式继承和属性 Object.prototype.isPrototypeOf(subObj) Object.prototype.hasOwnProperty(propKey) Object.prototype.propertyIsEnumerable(propKey)
['a', 'b'].length // 2 ['a', 'b',].length // 2 ['a', 'b', ,].length // 3
数组是由索引到值的映射,这意味这数组能够有空缺,索引的个数小于数组的长度说明数组为空缺数组。
var a = new Array(5); a[1] = 1; a[4] = 4; // a[0], a[2], a[3]都未赋值,a为空缺数组
['a', , 'b'].forEach(function (x, i) { console.log(i + ': ' + x); }); // 0: a // 2: b
['a', , 'b'].every(function (x) { return typeof x === 'string' }); // true
['a', , 'b'].map(function (x, i) { return i + '.' + x; }); // ['0.a', , '2.b']
['a', , 'b'].filter(function (x) { return true; }); // ['a', 'b']
['a', , 'b'].join('-'); // a--b ['a', , 'b', undefined, 'c', null,'d'].join('-'); //a--b--c--d
['a', , 'b'].sort(); // ['a', 'b', ,]
for-in循环能够正确列出属性建, 跳过空缺
for (var key in ['a', , 'b']) { console.log(key) } // 0 // 2 for (var key in ['a', undefined, 'b']) { console.log(key) } // 0 // 1 // 2
apply()把每一个空缺转化为undefined参数。
function f () { return Array.prototype.slice.call(arguments); } f.apply(null, [,,,]); // [undefined, undefined, undefined] Array.apply(null, [,,,]); // [undefined, undefined, undefined]
Array.isArray(obj) 判断obj是否为一个数组,可以正确处理跨域对象。
移除索引0处的元素并返回该元素。随后元素的索引依次减1:
var arr = ['a', 'b']; var first = arr.shift(); // 'a' console.log(arr); // ['b']
在数组前面插入指定的元素,返回新的数组长度
var arr = ['a', 'b']; arr.unshift('c', 'd'); // 4 console.log(arr); // ['c', 'd', 'a', 'b']
移除数组最后的元素并返回该元素
var arr = ['a', 'b']; var last = arr.pop(); // 'b' console.log(arr); // ['a']
在数组的最后追加指定的元素,返回新的数组长度
var arr = ['a', 'b']; arr.push('c', 'd'); // 4 console.log(arr); // ['a', 'b', 'c', 'd']
小技巧: 可使用apply函数将一个数组追加到另外一个数组的后面
var arr1 = ['a', 'b']; var arr2 = ['c', 'd']; Array.prototype.push.apply(arr1, arr2); console.log(arr1); // ["a", "b", "c", "d"]
从索引start位置开始,删除deleteCount个元素,并在该位置插入给定元素, 返回删除的元素组成的数组
var arr = ['a', 'b', 'c', 'd']; arr.splice(1, 2, 'X'); // ['b', 'c'] console.log(arr); // ['a', 'X', 'd']
注: start能够为负值,表示从倒数几位开始。deleteCount是可选的,若是省略,移除从start位置开始的全部元素
var arr = ['a', 'b', 'c', 'd']; arr.splice(-2); // ['c', 'd'] console.log(arr); // ['a', 'd']
颠倒数组中的元素,并返回指向原数组的引用:
var arr = ['a', 'b', 'c']; arr.reverse(); // ['c', 'b', 'a'] console.log(arr); // ['c', 'b', 'a']
数组排序, 并返回排序后的数组
var arr = ['banana', 'apple', 'pear', 'orange']; arr.sort() // ['apple', 'banana', 'orange', 'pear']; console.log(arr); // ['apple', 'banana', 'orange', 'pear'];
注: 排序是经过将元素转换为字符串再进行比较,这意味着数字不是按照数值进行排序
[-1, -20, 7, 50].sort(); // [-1, -20, 50, 7]
能够经过compareFunction来解决该问题,该函数的签名为:
function compareFunction (a, b)
比较参数a和b的值,返回的规则以下:
小于0的整数, a < b, 则a排在b的前面
等于0, a === b
大于0的整数, a > b, 则a排在b的后面
注: 对于数字,通常的就简单的返回a-b, 可能致使数值溢出,为了防止这种状况,可能须要更复杂的逻辑
[-1, -20, 7, 50].sort(function (a, b) { return a < b ? -1 : (a > b ? 1 : 0); }); // [-20, -1, 7, 50]
建立一个新数组,其中包含接受者的全部元素,其次是arr1中的全部元素,依次类推,若是其中一个参数不是数组, 当中元素添加到数组中
var arr = ['a', 'b']; var newArray = arr.concat('c', ['d', 'e']); // ["a", "b", "c", "d", "e"] console.log(newArray); // ["a", "b", "c", "d", "e"] console.log(arr); // ['a', 'b']
把数组中从start开始到end(不包含end)的元素复制到新数组中
['a', 'b', 'c', 'd'].slice(1, 3) // ['b', 'c'] ['a', 'b', 'c', 'd'].slice(1) // ['b', 'c', 'd'] ['a', 'b', 'c', 'd'].slice() // ['a', 'b', 'c', 'd']
注: 不包含end时,拷贝从start开始到最后的全部元素, 若是不传start和end参数,拷贝数组, start和end均可以是负值,表示从倒数开始
对全部数组元素应用toString()建立字符串, 并使用separator链接字符,若是缺乏separator,默认使用','
[3, 4, 5].join('-') // 3-4-5 [3, 4, 5].join() // 3,4,5 [3, 4, 5].join('') // 345
注:若是数组中某个元素为undefined, null或者空缺, 调用join方法是,会将该元素转换成空字符串
[undefined, null, 'a'].join('#') // ##a [undefined, , 'a'].join('#') // ##a
从数组的startIndex位置开始查找searchValue,返回第一次出现searchValue的索引,没有找到,就返回-1。缺乏startIndex, 查找整个数组
[3, 1, 17, 1, 4].indexOf(1); // 1 [3, 1, 17, 1, 4].indexOf(1, 2); // 3
注:查找时使用的是严格相等, 不能查找NaN
[NaN].indexOf(NaN); // -1
从数组的startIndex位置开始反向查找searchValue,返回第一次出现searchValue的索引,没有找到,就返回-1。缺乏startIndex, 查找整个数组。查找时使用的是严格相等
[3, 1, 17, 1, 4].indexOf(1); // 3 [3, 1, 17, 1, 4].indexOf(1, -3); // 1 [3, 1, 17, 1, 4].indexOf(1, 2); // 1
能够划分为三种迭代方法:
检查方法: 主要观察数组的内容(forEach, every, some)
转化方法: 从已有的数组中得到新数组(map, filter)
归约方法: 基于接受者的元素计算出结果(reduce, reduceRight)
遍历数组中的元素
var arr = ['apple', 'banana', 'pear']; arr.forEach(function (elem) { console.log(elem); }); // apple // banana // pear
注: 存在一个缺陷,不支持break
或者相似于提早终止循环的处理,除非throw Error。
若是对每一个元素。回调函数都返回true,则every方法返回true, 若是某个元素回调函数返回false, 则中止迭代。相似全称量词
// 检查数组中的元素是否所有为偶数 function isEven(x) { return x % 2 === 0 } [2, 4, 6].every(isEven); // true [2, 4, 5].every(isEven); // false
注: 若是为空数组,返回true,不会调用callback方法
[].every(function () { throw new Error('Empty array') }); // true
若是对其中某个元素。回调函数返回true,则some方法返回true, 若是某个元素回调函数返回true, 则中止迭代。相似存在量词
// 检查数组中的元素是否存在偶数 function isEven(x) { return x % 2 === 0 } [1, 3, 5].some(isEven); // false [2, 2, 3].some(isEven); // true
注: 若是为空数组,返回false,不会调用callback方法
[].some(function () { throw new Error('Empty array') }); // false
转化数组的每一个元素都是原数组中元素调用回调函数callback后的结果
[1, 2, 3],map(function (elem) { return 2 * elem; }); // [2, 4, 6]
转化数组的元素都是原数组中元素调用回调函数callback返回true的元素
[1, 0, 3, 0].filter(function (x) { return !!x; }); // [1, 3]
从左至右进行迭代,其中callback参数的结构为:
function callback(previousValue, currentValue, currentIndex, array);
除初次调用外,每次调用callback时,参数previousValue是上一次回调函数的返回值。初次调用回调函数有两种状况
提供显式initialValue参数,previousValue就是initialValue,而currentValue为数组中的第一个元素
未提供显式initialValue参数,previousValue就是第一个元素,而currentValue为数组中的第二个元素
reduce方法返回最后一次调用回调函数时的结果
function add (pre, cur) { return pre + cur; } [1, 10, -3].reduce(add); // 8
注: 只有一个元素的数组调用reduce,则返回该元素
function add (pre, cur) { return 2 * pre + 3 * cur; } function add2 (pre, cur) { return 1; } [7].reduce(add); // 7 [7].reduce(add2); // 7
注: 若是对空数组调用reduce, 必须指定initialValue, 不然会抛出异常
[].reduce(add); // Uncaught TypeError: Reduce of empty array with no initial value
工做原来与Array.prototype.reduce类似,可是是从右至左归约
javascript中存在一类对象看起来像数组,实际上不是,能够经过索引访问元素具备length属性,但没有数组的其余实例属性。
类数组对象主要有:特殊对象arguments、DOM节点列表和字符串。
咱们可使用泛型方法来使类数组对象防访问数组原型上的方法。
分组的语法:
(<<pattern>>) 捕获分组。任何匹配pattern的内容均可以经过反向引用访问或做为匹配结果。
(?:<<pattern>>) 非捕获分组。仍然根据pattern匹配,但不保存捕获的内容。分组没有数字能够引用。
12...依次类推称为方向引用;他们指向以前匹配的分组。第一个数字必须不是0
/^(a+)-\1$/.test('a-a'); // true /^(a+)-\1$/.test('aaa-aaa'); // true /^(a+)-\1$/.test('aaa-a'); // false
注:方向引用保证破折号先后的字符数一致
使用方向引用来匹配HTML标签
var tagName = /<([^>]+)>[^<]*<\/\1>/; tagName.exec('<b>bold</b>')[1] // b tagName.exec('<strong>text</strong>')[1] // strong tagName.exec('<strong>text</stron>')[1] // TypeError: Cannot read property '1' of null
? 表示从未匹配或只匹配一次
表示从匹配零次或屡次
表示匹配一次或屡次
{n} 表示彻底匹配n次
{n, } 表示匹配至少n次
{n, m} 表示匹配至少n次,最多m次
默认状况下,量词是贪婪匹配的,他们会尽量多的匹配,若是想使用勉强匹配(尽量少),能够经过量词后面加问号(?)
// 贪婪匹配 '<a> <strong></strong>'.match(/^<(.*)>/)[1] // a> <strong></strong // 勉强匹配 '<a> <strong></strong>'.match(/^<(.*?)>/)[1] // a
注:*?是十分有用的模式,它能够匹配一切,直到后面的原子出现。
上述匹配HTML标签的正则能够改成
var tagName = /<(.+?)>.*?<\/\1>/; tagName.exec('<b>bold</b>')[1] // b tagName.exec('<strong>text</strong>')[1] // strong tagName.exec('<strong>text</stron>')[1] // TypeError: Cannot read property '1' of null
^ 只匹配输入的开始位置
$ 只匹配输入结束位置
b 只匹配单词的边界。不要与[b]混淆,它匹配一个退格。
B 只匹配非单词边界
(?=<<pattern>>) 正向确定断言:只匹配pattern所匹配的接下来的内容。pattern只是用来向前查找,但会忽略匹配的pattern部分
(?!<<pattern>>) 正向确定断言:只匹配pattern不匹配的接下来的内容。pattern只是用来向前查找,但会忽略匹配的pattern部分
匹配单词边界
/\bell\b/.test('hello'); // false /\bell\b/.test('ello'); // false /\bell\b/.test('a ell v'); // true
经过B匹配单词的内部元素
/\Bell\B/.test('ell'); // false /\Bell\B/.test('ello'); // false /\Bell\B/.test('hello'); // true
标识是正则表达式字面量的后缀和正则表达式构造函数的参数;它修改正则表达是的匹配行为。
简称 | 全称 | 描述 |
---|---|---|
g | global | 给定的正则表达式能够匹配屡次,它会影响几种方法,尤为是String.prototype.replace() |
i | ignoreCase | 试图匹配给定的正则表达式时忽略大小写 |
m | multiline | 在多行模式时,开始操做符^和结束操做符$匹配每一行,而不是输入的整个字符串 |
简称用于正则字面量后缀和构造函数参数,全称用于正则表达式对象的属性
标识: 布尔值表示设置什么标志。
global(全局): 是否设置/g标识 ignoreCase(忽略大小写): 是否设置了/i标识 multiline(多行): 是否设置/m标识
屡次匹配数据(设置了/g标识)
lastIndex: 下次继续查找的起始索引
var regex = /abc/i; regex.ignoreCase; // true regex.multiline; // false
test()方法用来检查正则表达式regex是否匹配字符串str:
regex.test(str)
若是没有设置/g标识,该方法只检查是否在str某处存在匹配;若是设置了/g标识,则该方法会屡次匹配regex并返回true,属性lastIndex包含最后一次匹配以后的索引
// 未设置/g var str = '_x_x'; /x/.test(str); // true /a/.test(str); // false // 设置/g var regex = /x/g; regex.lastIndex; // 0 regex.test(str); // true regex.lastIndex; // 2 regex.test(str); // true regex.lastIndex; // 4 regex.test(str); // false
search()方法查找str匹配regex的位置
str.search(regex)
若是存在匹配返回匹配位置的索引,不然,返回值为-1, 进行查找时,regex的global和lastIndex属性被忽略(其中lastIndex没有改变)
'abba'.search(/b/); // true 'abba'.search(/B/i); // true 'abba'.search(/x/i); // true
注:若是search()的参数不是正则表达式,它被转换为正则:
'aaab'.search('^a+b+$'); // 0
在str匹配regex的同时捕获分组
var matchData = regex.exec(str);
若是没有匹配,matchData为null。不然,matchData为匹配结果,是带有两个附属属性的数组
(1) 数组元素
元素0是完整正则表达式的匹配结果。
元素n>1是捕获的分组N。
(2)属性
input 是输入的完整字符串
index 是查找到匹配处的索引
若是未设置/g标识,只返回第一次匹配的结果:
var regex = /a(b+)/; regex.exec('_abbb_ab_'); // ['abbb', 'bbb', index: 1, input: '_abbb_ab_'] regex.lastIndex; // 0
若是设置了/g标识,能够反复调用exec()方法返回全部的匹配项,返回值null表示没有任何匹配。属性lastIndex表示下次匹配从哪里开始
var regex = /a(b+)/g; var str = '_abbb_ab_'; console.log(regex.exec(str)); // ['abbb', 'bbb', index: 1, input: '_abbb_ab_'] console.log(regex.lastIndex); // 5 console.log(regex.exec(str)); // ['ab', 'b', index: 6, input: '_abbb_ab_'] console.log(regex.lastIndex); // 8 regex.exec(str); // null
使用循环遍历全部的匹配项
var regex = /a(b+)/g; var str = '_abbb_ab_'; var match; while(match = regex.exec(str)) { console.log(match[1]); } // bbb // b
var matchData = str.match(regex);
若是未设置/g标识,该方法相似与RegExp.prototype.exec()
'abba'.match(/a(b+)/); // ["abb", "bb", index: 0, input: "abba"]
若是设置了/g标识,则返回str中含有全部匹配的子字符串的数组;若是没有任何匹配,则返回null
'_abbb_ab_'.match(/a(b+)/g); // ["abbb", "ab"]
存在两个参数: search, replacement
search: 字符串或者正则表达式。
1) 字符串: 在字符串中找到匹配的字面量,只能替换一次出现的匹配项,暂不存在 (replaceAll函数),想要替换屡次出现的匹配项,必须使用正则表达式/g标识。 2) 正则表达式: 对输入的字符串进行匹配。若是想替换屡次,必须使用/g标识
replacement: 字符串或者函数。
1) 字符串: 描述如何替换找到的匹配项), 使用该字符串替换匹配项,替换字符串中的$ 符号容许使用彻底匹配或者匹配分组进行替换 2) 函数: 执行替换并提供参数匹配信息.
'iixxxixx'.replace('i', 'o') // oixxxixx 'iixxxixx'.replace(/i/, 'o') // oixxxixx 'iixxxixx'.replace(/i/g, 'o') // ooxxxoxx // 使用$符号 'iixxxixx'.replace(/i+/g, '($&)') // (ii)xxx(i)xx 'iixxxixx'.replace(/(i+)/g, '($1)') // (ii)xxx(i)xx // 使用函数替换 function repl(search, group, offset, input) { return '{ search: ' + search.toUpperCase() + ', group: ' + group + ', offset: ' + offset + ' }'; } 'iixxxixx'.replace(/(i+)/g, repl) // { search: II, group: ii, offset: 0 }xxx{ search: I, group: i, offset: 5 }xx
内容用来逐字替换匹配项,惟一例外是特殊字符美圆符号($),它会启动替换指令
分组:$n在匹配中插入分组n。n必须大于等于1($0没有任何特殊含义)
匹配的子字符串:
1) $\` (反引号)插入匹配项以前的文本 2) $& 插入完整的匹配项 3) $' (单引号)插入匹配项以后的文本
$$ 插入单个$字符
'axb cxd'.replace(/x/g, "($`,$&,$')"); // a(a,x,b cxd)b c(axb c,x,d)d '"foo" and "bar"'.replace(/"(.*?)"/g, '#$1#'); // #foo# and #bar#
若是replacement为函数,它须要对替换匹配项的字符串进行处理。签名以下:
function replacement (search, group_1, ..., group_n, offset, input){}
search与前面介绍的$&(完整的匹配项)相同, offset表示找到匹配项的位置,input是正在被匹配的字符串
search: 正则表达式匹配到的字符串
group: 若是存在分组,该值为匹配到的分组值, 可变参数, 匹配到分组有多少个,这个参数就有多少个, 若是不存在,表示匹配到子字符所在原字符串的位置
offset(倒数第二个参数): 匹配到子字符所在原字符串的位置
input(最后一个参数): 原字符串
function replaceFunc (match) { return 2 * match; } '3 peoples and 5 oranges'.replace(/\d+/g, replaceFunc); // 6 peoples and 10 oranges
/g
的一些问题正则表达式设置了/g
标识,有些方法必须屡次(循环)调用才能放回全部结果。这些方法以下所示
RegExp.prototype.test()
RegExp.prototype.exec()
正则表达式做为迭代器成为结果序列的指针时,会被不正确地使用。这致使的问题以下:
/g
的正则表达式不能内联// 反模式 var count = 0; while (/a/g.test('babaa')) count++; // 正确用法 var count = 0; var regex = /a/g; while (regex.test('babaa')) count++;
上述第一种状况中会建立无限循环,每次循环迭代都会建立一个新的正则表达式,致使从新开始迭代。
// 反模式 function extractQuoted(str) { var match; var result = []; while ((match = /"(.*?)"/g.exec(str)) !== null) { result.push(match[1]); } return result; } // 会致使无限循环 // 正确的方法 function extractQuoted(str) { var QUOTE_REGEX = /"(.*?)"/g; var match; var result = []; while ((match = QUOTE_REGEX.exec(str)) !== null) { result.push(match[1]); } return result; } extractQuoted('"hello", "world"'); // ["hello", "world"]
注:为了不上述这种无限循环的状况,最好的解决办法就是在任何状况下,都不使用内联正则表达式,这要求咱们造成一个良好的编码习惯。
/g
的正则表达式做为参数须要屡次调用test()和exec()方法时,把正则做为参数传递给方法时必需要当心。必须设置/g
标识,为了安全起见,应该设置lastIndex为0
/g
的正则表达式当你引用不是新建立的正则表达式时,在把它做为迭代器前,须要手动把lastIndex设置为0。因为迭代依赖lastIndex,这种正则表达式不能同时用于多个迭代。
function countOccurrences(regex, str) { var count = 0; while (regex.test(str)) count++; return count; } countOccurrences(/x/g, '_x_x'); // 2 // 问题一: 若是不加/g标识,会进入无限循环 countOccurrences(/x/, '_x_x'); // 无限循环 // 问题二: lastIndex未设置为0 var regex = /x/g; regex.lastIndex = 2; countOccurrences(regex, '_x_x'); // 1 // 修复上述两个问题 function countOccurrences(regex, str) { if (!regex.global) { throw new Error('Please set flag /g of regex'); } var origLastIndex = regex.lastIndex; // store regex.lastIndex = 0; var count = 0; while (regex.test(str)) count++; regex.lastIndex = origLastIndex; return count; } // 更简单的方式,使用String.prototype.match function countOccurrences(regex, str) { if (!regex.global) { throw new Error('Please set flag /g of regex'); } return (str.match(regex) || []).length; }
给制定的字符串拼装成正则表达式,全部特殊是字符都须要进行转义。
function quoteText(text) { return text.replace(/[\\^$.*+?()[\]{}|=!<>:-]/g, '\\$&'); } console.log(quoteText('*All* (most?) aspects.')); // \*All\* \(most\?\) aspects\.
/aa/.test('xaay'); // true /^aa$/.test('xaay'); // false
一种特殊状况:函数能够把正则表达式当作参数,用于过滤,若是缺乏这个参数,须要提供一个能够匹配一切的默认值
空的正则表达式能够匹配一切
new RegExp('').test('dfadsfdas'); // true new RegExp('').test(''); // true
空的正则表达式应该是\/\/
, 可是它被解释为JavaScript的注释。全部咱们可使用最接近的字面量代替\/(?:)\/
(空的非捕获分组)。这个分组能够匹配一切并且不捕获任何字符串。
new RegExp(''); // /(?:)/
空的正则表达式相反的正则表达式
var never = /.^/; never.test('asdsad'); // false never.test(''); // false
.(点) 匹配除了行结束符的一切字符。使用[\s\S]能够正则匹配一切
转义字符
\d 匹配数字([0-9]); \D 匹配非数字([^0-9])。 \w 匹配拉丁字母数字的字符以及下划线([a-zA-Z0-9_]); \W 匹配其余字符。 \s 匹配全部空白字符(空格、制表、换行符等); \S 匹配全部的非空白字符。 须要转移的字符: * . ? + $ ^ [ ] ( ) { } | \ /
字符类(字符集合): [...]和[^...]
源字符: [abc](除了\]-的全部匹配其自己的字符) 转义字符: [\d\w] 范围: [A-Za-z0-9]
分组
捕获分组: (...); 方向引用\1 非捕获分组: (?:...)
贪婪匹配
? * + {n}, {n, }, {n, m}
非贪婪: 把?放在任何贪婪量词后面
输入的开始和结束: ^ $。
单词的边界,非单词边界: b B。
正向确定查找: (?=...) 匹配紧随其后的模式,但其会被忽略
正向否认查找: (?!...) 不匹配紧随其后的模式,但其会被忽略
字面量: /abc/i (加载时编译)
构造函数: new RegExp('zxc', 'igm'); (运行时编译)
global(全局): /g(影响正则表达式的一些方法)。
ignoreCase(忽略大小写): /i 。
multiline(多行): /m (^和$匹配每一行,而不是完整的输入)。
regexp.test(str): 是否存在匹配
不设置`/g`: 是否在某处存在匹配 设置`/g`: 存在多少次匹配就返回多少次true
str.search(regex): 在哪一个全部存在匹配
regexp.exec(str): 捕获分组
不设置`/g`: 只捕获第一次匹配的分组 设置`/g`: 捕获全部匹配的分组
str.match(regexp): 捕获分组或返回全部匹配的字符串
不设置`/g`: 捕获分组 设置`/g`: 返回全部匹配的子字符串数组
str.replace(search, replacement): 查找和替换
search: 字符串和正则表达式(使用后者,设置/g) replacement: 字符串(使用$1, 以此类推)或函数(arguments[1]是分组1, 以此类推)返回字符串
在uri中咱们用百分号来编码特殊字符,除了下列字符,其他的特殊字符都会被编码。
URI字符: ; , / ? : @ & = + $ #
下面字符也不会被编码: a-z A-Z 0-9 - _ . ! ~ * ' ( )
encodeURI('http://example.com/Fur Elise/'); // http://example.com/Fur%20Elise/
除了下列字符,全部字符都会被百分号编码(URI字符也会被编码):
下面字符也不会被编码: a-z A-Z 0-9 - _ . ! ~ * ' ( )
encodeURIComponent('http://example.com/Fur Elise/'); // http%3A%2F%2Fexample.com%2FFur%20Elise%2F
对已经进行encodeURI编码的uri进行解码操做
decodeURI('http://example.com/Fur%20Elise/'); // http://example.com/Fur Elise/
对已经进行encodeURIComponent编码的uri进行解码操做, 全部的百分号编码都会被解码
decodeURIComponent('http%3A%2F%2Fexample.com%2FFur%20Elise%2F'); // http://example.com/Fur Elise/
在Internet Explorer9中存在一个bug。在IE9中,console对象只有当开发者工具栏被打开过至少一次,才会存在。
这意味着若是你的代码引用了console对象,同时又没有预先打开开发者工具栏,你可能会获得一个引用错误。
为了确保兼容性,最好在使用console对象以前先判断其是否存在。
CJS的主要化身是Node.js模块,其特色:
紧凑的语法
同步加载的设计
主要用于服务端
AMD 最典型的实现就是Requirejs, 其特色:
AMD语法稍微复杂,但不经过eval()或者静态编译步骤就能够工做
异步加载的设计
主要用于浏览器
要将任意值转换成数字或者字符串,首先会被转换成任意的原始值,而后在转换成最终的结果。
ECMAScript规范中有一个内部函数, ToPrimitive()(不能访问),可以实现这个功能。签名以下:
ToPrimitive(input, PreferredType?)
可选参数PreferredType
代表转换后饿类型:它能够是Number
和String
,具体取决于ToPrimitive的结果是但愿转换成数字仍是字符串
若是PreferredType
是Number
,会执行如下步骤。
(1) 若是input是原始值,返回这个值。
(2) 不然,若是input是对象,调用input.valueOf()。若是结果是原始值,返回结果。
(3) 不然,调用input.toString()。若是结果是原始值,返回结果。
(4) 不然,抛出一个TypeError(说明输入转换原始值出错了)
若是PreferredType
是String
,会执行如下步骤。
(1) 若是input是原始值,返回这个值。
(2) 不然,若是input是对象,调用input.toString()。若是结果是原始值,返回结果。
(3) 不然,调用input.valueOf()。若是结果是原始值,返回结果。
(4) 不然,抛出一个TypeError(说明输入转换原始值出错了)
PreferredType也能够省略,这种状况下,日期会被认为是String而其余值会被认为是Number。所以+操做符和===运算符能够操做ToPrimitive()。
ToPrimitive()实战
valueOf的默认实现会返回this,而toString()的默认实现会返回类型信息
var empty = {}; empty.valueOf() === empty; // true empty.toString(); // '[object Object]'
Number() 跳过了valueOf()而且将toString()执行结果转换为数字,因此,它将'[object Object]'转换成了NaN
Number({}); // NaN
下面对象重写了valueOf(), 这会影响Number(), 可是不会对String()形成任何改变
var n = { valueOf: function () { return 123; } }; Number(n); // 123 String(n); // '[object Object]'
下面对象重写了toString()方法,由于结果会转换成数字,Number()返回了一个数字
var s = { toString: function () { return '7'; } }; String(s); // '7' Number(s); // 7
注: 我的笔记,持续更新