摘要:字符串在字符串中找到匹配的字面量,只能替換一次出現的匹配項,暫不存在函數,想要替換多次出現的匹配項,必須使用正則表達式標識。這符合賦值改變但不破壞繼承屬性的理念。二十七數組構造函數判斷是否為一個數組,能夠正確處理跨域對象。
一、String, Number, Boolean等包裝類型是對象,JavaScript沒有比較對象的方法,即使通過寬松比較相等==
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對象三、String.prototype.split(separator?, limit?)
作用: 通過指定邊界(separator)將字符串分割成子字符串,返回字符串組成的數組。
separator: 可選,可以為字符串或正則表達式。不傳的話,將原字符串封裝在數組中返回
limit: 可選, 若傳入,最多返回數組中limit個子字符串
注:若separator為包含子表達式分組的正則表達式,子表達式匹配的字符串也會作為數組中的元素返回。
"a, b , ".split(/(,)/) # ["a", ",", " b ", ",", " "]四、String.prototype.match(regexp)
作用: 捕獲分組或返回所有匹配的子字符串
注: 若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五、String.prototype.replace(search, replacement)
存在兩個參數: 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 }xx1. replacement為字符串
內容用來逐字替換匹配項,唯一例外是特殊字符美元符號($),它會啟動替換指令
分組:$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#2. replacement為函數
如果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六、檢查value是否為對象
function isObject (value) { return value === Object(value); }七、Array.prototype.forEach()的thisValue
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) } }八、使用給定的prototype創建新對象
使用方法: 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 "#
這符合賦值改變但不破壞繼承屬性的理念。如果一個繼承屬性是只讀的,應該禁止所有修改操作
十六、枚舉性影響下列操作1) for-in // 循環所有可枚舉屬性(自有+繼承) 2) Object.keys() // 列出所有自有可枚舉屬性 2) JSON.stringify() // 所有自有可枚舉屬性十七、保護對象之防止擴展(Object.preventExtensions())
不能添加屬性,可以刪除屬性, 可以修改已有自有屬性
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
十八、保護對象之封閉(Object.seal())不能添加屬性,且不能刪除屬性, 只能修改已有自有屬性。
(封閉 === 防止擴展 + 不能刪除屬性)
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
十九、保護對象之凍結(Object.freeze())不能添加屬性,不能刪除屬性, 同時也修改已有自有屬性。
(凍結 === 封閉 + 不能修改屬性)
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.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的實例,因為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()來判斷是否為數組
二十三、備忘錄: 對象的使用 1. 對象字面量Test
var jane = { name: "Jane", "not an indentifier": 123, describe: function () { return "Person named " + this.name; } } jane.describe() // Person named Jane2. 點操作符(.):通過固定鍵值訪問屬性
obj.propKey // 訪問 obj.propKey = value // 賦值 delete obj.propKey // 刪除3. 中括號操作符([]): 通過計算出的鍵值訪問屬性
obj["propKey"] // 訪問 obj["propKey"] = value // 賦值 delete obj["propKey"] // 刪除4.獲取和設置原型
Object.create(proto, propDescObj?) // 創建指定原型的對象 Object.getPrototypeOf(obj) // 獲取原型5.屬性的遍歷和檢測
Object.keys(obj) Object.getOwnPropertyNames(obj) for (var propKey in obj) Object.prototype.hasOwnProperty.call(obj, propkey)6. 通過描述符獲取和定義屬性特性
// 定義 Object.defineProperty(obj, propKey, propDesc) Object.defineProperties(obj, propDescObj) Object.create(obj, propDescObj) // 獲取 Object.getOwnPropertyDescriptor(obj, propKey)7. 保護對象: 防止擴展、封閉、凍結
// 防止擴展: 不能添加屬性,能刪除屬性或修改屬性值 Object.preventExtensions(obj) Object.isExtensible(obj) // 封裝: 不能添加或者刪除屬性,能修改屬性值 Object.seal(obj) Object.isSealled(obj) // 凍結: 不能添加或者刪除屬性,也不能修改屬性值 Object.freeze(obj) Object.isFrozen(obj)8. 所有對象的方法
// 將對象轉換為基本類型的值 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為空缺數組二十六、數組中某些方法會忽略空缺 1. 數組遍歷方法 1) forEach()遍歷時會跳過空缺
["a", , "b"].forEach(function (x, i) { console.log(i + ": " + x); }); // 0: a // 2: b2) every()也會跳過空缺(類似的還有some()方法)
["a", , "b"].every(function (x) { return typeof x === "string" }); // true3) map()雖然會跳過空缺,但會保留空缺
["a", , "b"].map(function (x, i) { return i + "." + x; }); // ["0.a", , "2.b"]4) filter()會去除空缺
["a", , "b"].filter(function (x) { return true; }); // ["a", "b"]2. 其他方法 1) join()會把空缺、undefined、null轉換成空的字符串
["a", , "b"].join("-"); // a--b ["a", , "b", undefined, "c", null,"d"].join("-"); //a--b--c--d2) sort()排序時保留空缺
["a", , "b"].sort(); // ["a", "b", ,]3. for-in循環
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 // 24. Function.prototype.apply()
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是否為一個數組,能夠正確處理跨域對象。
二十八、數組的原型方法 1. 添加和刪除元素(破壞性的) 1) Array.prototype.shift()移除索引0處的元素并返回該元素。隨后元素的索引依次減1:
var arr = ["a", "b"]; var first = arr.shift(); // "a" console.log(arr); // ["b"]2) Array.prototype.unshift(elem1?, elem2?, ...)
在數組前面插入指定的元素,返回新的數組長度
var arr = ["a", "b"]; arr.unshift("c", "d"); // 4 console.log(arr); // ["c", "d", "a", "b"]3) Array.prototype.pop()
移除數組最后的元素并返回該元素
var arr = ["a", "b"]; var last = arr.pop(); // "b" console.log(arr); // ["a"]4) Array.prototype.push(elem1?, elem2?, ...)
在數組的最后追加指定的元素,返回新的數組長度
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"]5) Array.prototype.splice(start, deleteCount?, elem1?, elem2?, ...)
從索引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"]2. 排序和顛倒元素順序(破壞性的) 1) Array.prototype.reverse()
顛倒數組中的元素,并返回指向原數組的引用:
var arr = ["a", "b", "c"]; arr.reverse(); // ["c", "b", "a"] console.log(arr); // ["c", "b", "a"]2) Array.prototype.sort(compareFunction?)
數組排序, 并返回排序后的數組
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]3. 合并、切分和連接(非破壞性) 1) Array.prototype.concat(arr1?, arr2?, ...)
創建一個新數組,其中包含接受者的所有元素,其次是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"]2) Array.prototype.slice(start?, end?)
把數組中從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都可以是負值,表示從倒數開始
3) Array.prototype.join(separator?)對所有數組元素應用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("#") // ##a4. 值的查找(非破壞性) 1) Array.prototype.indexOf(searchValue, startIndex?)
從數組的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); // -12) Array.prototype.lastIndexOf(searchValue, startIndex?)
從數組的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); // 15. 迭代(非破壞性)
可以劃分為三種迭代方法:
檢查方法: 主要觀察數組的內容(forEach, every, some)
轉化方法: 從已有的數組中獲得新數組(map, filter)
歸約方法: 基于接受者的元素計算出結果(reduce, reduceRight)
1) Array.prototype.forEach(callback, thisValue?)遍歷數組中的元素
var arr = ["apple", "banana", "pear"]; arr.forEach(function (elem) { console.log(elem); }); // apple // banana // pear
注: 存在一個缺陷,不支持break或者類似于提前終止循環的處理,除非throw Error。
2) Array.prototype.every(callback, thisValue?)如果對每個元素。回調函數都返回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") }); // true3) Array.prototype.some(callback, thisValue?)
如果對其中某個元素。回調函數返回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") }); // false4) Array.prototype.map(callback, thisValue?)
轉化數組的每個元素都是原數組中元素調用回調函數callback后的結果
[1, 2, 3],map(function (elem) { return 2 * elem; }); // [2, 4, 6]5) Array.prototype.filter(callback, thisValue?)
轉化數組的元素都是原數組中元素調用回調函數callback返回true的元素
[1, 0, 3, 0].filter(function (x) { return !!x; }); // [1, 3]6) Array.prototype.reduce(callback, initialValue?)
從左至右進行迭代,其中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 value7) Array.prototype.reduceRight(callback, initialValue?)
工作原來與Array.prototype.reduce相似,但是是從右至左歸約
二十九、類數組對象javascript中存在一類對象看起來像數組,實際上不是,可以通過索引訪問元素具有length屬性,但沒有數組的其他實例屬性。
類數組對象主要有:特殊對象arguments、DOM節點列表和字符串。
我們可以使用泛型方法來使類數組對象防訪問數組原型上的方法。
三十、正則表達式原子(分組)分組的語法:
(<
(?:<
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("bold")[1] // b tagName.exec("text")[1] // strong tagName.exec("text")[1] // TypeError: Cannot read property "1" of null三十一、正則表達式量詞
? 表示從未匹配或只匹配一次
表示從匹配零次或多次
表示匹配一次或多次
{n} 表示完全匹配n次
{n, } 表示匹配至少n次
{n, m} 表示匹配至少n次,最多m次
默認情況下,量詞是貪婪匹配的,他們會盡可能多的匹配,如果想使用勉強匹配(盡可能少),可以通過量詞后面加問號(?)
// 貪婪匹配 " ".match(/^<(.*)>/)[1] // a> ".match(/^<(.*?)>/)[1] // a
注:*?是十分有用的模式,它可以匹配一切,直到后面的原子出現。
上述匹配HTML標簽的正則可以改為
var tagName = /<(.+?)>.*?1>/; tagName.exec("bold")[1] // b tagName.exec("text")[1] // strong tagName.exec("text")[1] // TypeError: Cannot read property "1" of null三十二、正則表達式斷言
^ 只匹配輸入的開始位置
$ 只匹配輸入結束位置
b 只匹配單詞的邊界。不要與[b]混淆,它匹配一個退格。
B 只匹配非單詞邊界
(?=<
(?!<
匹配單詞邊界
/ell/.test("hello"); // false /ell/.test("ello"); // false /ell/.test("a ell v"); // true
通過B匹配單詞的內部元素
/BellB/.test("ell"); // false /BellB/.test("ello"); // false /BellB/.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三十五、RegExp.prototype.test: 是否存在匹配
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三十六、String.prototype.search: 匹配位置的索引
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三十七、RegExp.prototype.exec: 捕獲分組
在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三十八、String.prototype.match: 捕獲分組已經返回所有匹配的子字符串
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"]三十九、String.prototype.replace: 查找和替換
存在兩個參數: 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 }xx1. replacement為字符串
內容用來逐字替換匹配項,唯一例外是特殊字符美元符號($),它會啟動替換指令
分組:$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#2. replacement為函數
如果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()
正則表達式作為迭代器成為結果序列的指針時,會被不正確地使用。這導致的問題如下:
1. 帶有/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"]
注:為了避免上述這種無限循環的情況,最好的解決辦法就是在任何情況下,都不使用內聯正則表達式,這要求我們形成一個良好的編碼習慣。
2. 帶/g的正則表達式作為參數需要多次調用test()和exec()方法時,把正則作為參數傳遞給方法時必須要小心。必須設置/g標識,為了安全起見,應該設置lastIndex為0
3. 共享帶有/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四十三、匹配一切或者什么都不匹配
一種特殊情況:函數可以把正則表達式當做參數,用于過濾,如果缺少這個參數,需要提供一個可以匹配一切的默認值
1. 匹配一切空的正則表達式可以匹配一切
new RegExp("").test("dfadsfdas"); // true new RegExp("").test(""); // true
空的正則表達式應該是//, 但是它被解釋為JavaScript的注釋。所有我們可以使用最接近的字面量代替/(?:)/(空的非捕獲分組)。這個分組可以匹配一切而且不捕獲任何字符串。
new RegExp(""); // /(?:)/2. 不匹配任何字符
空的正則表達式相反的正則表達式
var never = /.^/; never.test("asdsad"); // false never.test(""); // false四十四、正則表達式備忘錄 1. 原子
.(點) 匹配除了行結束符的一切字符。使用[sS]可以正則匹配一切
轉義字符
d 匹配數字([0-9]); D 匹配非數字([^0-9])。 w 匹配拉丁字母數字的字符以及下劃線([a-zA-Z0-9_]); W 匹配其他字符。 s 匹配所有空白字符(空格、制表、換行符等); S 匹配所有的非空白字符。 需要轉移的字符: * . ? + $ ^ [ ] ( ) { } | /
字符類(字符集合): [...]和[^...]
源字符: [abc](除了]-的所有匹配其本身的字符) 轉義字符: [dw] 范圍: [A-Za-z0-9]
分組
捕獲分組: (...); 方向引用1 非捕獲分組: (?:...)2. 量詞
貪婪匹配
? * + {n}, {n, }, {n, m}
非貪婪: 把?放在任何貪婪量詞后面
3. 斷言輸入的開始和結束: ^ $。
單詞的邊界,非單詞邊界: b B。
正向肯定查找: (?=...) 匹配緊隨其后的模式,但其會被忽略
正向否定查找: (?!...) 不匹配緊隨其后的模式,但其會被忽略
4. 析取(或): | 5. 創建正則表達式字面量: /abc/i (加載時編譯)
構造函數: new RegExp("zxc", "igm"); (運行時編譯)
6. 標識global(全局): /g(影響正則表達式的一些方法)。
ignoreCase(忽略大小寫): /i 。
multiline(多行): /m (^和$匹配每一行,而不是完整的輸入)。
7. 方法
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, 以此類推)返回字符串四十五、文字的編碼和解碼 1. encodeURI(uri)
在uri中我們用百分號來編碼特殊字符,除了下列字符,其余的特殊字符都會被編碼。
URI字符: ; , / ? : @ & = + $ #
下面字符也不會被編碼: a-z A-Z 0-9 - _ . ! ~ * " ( )
encodeURI("http://example.com/Fur Elise/"); // http://example.com/Fur%20Elise/2. encodeURIComponent(uri)
除了下列字符,所有字符都會被百分號編碼(URI字符也會被編碼):
下面字符也不會被編碼: a-z A-Z 0-9 - _ . ! ~ * " ( )
encodeURIComponent("http://example.com/Fur Elise/"); // http%3A%2F%2Fexample.com%2FFur%20Elise%2F3. decodeURI(encodeURI)
對已經進行encodeURI編碼的uri進行解碼操作
decodeURI("http://example.com/Fur%20Elise/"); // http://example.com/Fur Elise/4. decodeURIComponent(encodeURIComponent)
對已經進行encodeURIComponent編碼的uri進行解碼操作, 所有的百分號編碼都會被解碼
decodeURIComponent("http%3A%2F%2Fexample.com%2FFur%20Elise%2F"); // http://example.com/Fur Elise/四十六、Console在IE9中存在兼容性問題
在Internet Explorer9中存在一個bug。在IE9中,console對象只有當開發者工具欄被打開過至少一次,才會存在。
這意味著如果你的代碼引用了console對象,同時又沒有預先打開開發者工具欄,你可能會得到一個引用錯誤。
為了確保兼容性,最好在使用console對象之前先判斷其是否存在。
CJS的主要化身是Node.js模塊,其特點:
緊湊的語法
同步加載的設計
主要用于服務端
2. 異步模塊定義(Asynchronous Module Definition, AMD)AMD 最典型的實現就是Requirejs, 其特點:
AMD語法稍微復雜,但不通過eval()或者靜態編譯步驟就可以工作
異步加載的設計
主要用于瀏覽器
四十八、算法: ToPrimitive() —— 將值轉換為原始值要將任意值轉換成數字或者字符串,首先會被轉換成任意的原始值,然后在轉換成最終的結果。
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
注: 個人筆記,持續更新
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81643.html
摘要:知識點變量作用域上方的函數作用域中聲明并賦值了,且在之上,所以遵循就近原則輸出等于。上方的函數作用域中被重新賦值,未被重新聲明,且位于之下,所以輸出全局作用域中的。上方利用方法進行對象的深拷貝可以避免源對象被篡改的可能。 前言 本文是我學習JavaScript過程中收集與整理的一些易錯知識點,將分別從變量作用域,類型比較,this指向,函數參數,閉包問題及對象拷貝與賦值這6個方面進行由...
摘要:知識點變量作用域上方的函數作用域中聲明并賦值了,且在之上,所以遵循就近原則輸出等于。上方的函數作用域中被重新賦值,未被重新聲明,且位于之下,所以輸出全局作用域中的。若執行則會輸出。上方利用方法進行對象的深拷貝可以避免源對象被篡改的可能。 前言 本文是我學習JavaScript過程中收集與整理的一些易錯知識點,將分別從變量作用域,類型比較,this指向,函數參數,閉包問題及對象拷貝與賦值...
摘要:針對于面向對象編程的。因為面向對象就是針對對象例子中的守候來進行執行某些動作。這就是閉包的用途之一延續變量周期。把變量放在閉包里面和放在全局變量里面,影響是一致的。 1.前言 這段時間,金三銀四,很多人面試,很多人分享面試題。在前段時間,我也臨時擔任面試官,為了大概了解面試者的水平,我也寫了一份題目,面試了幾個前端開發者。在這段時間里面,我在學,在寫設計模式的一些知識,想不到的設計模式...
摘要:我對知乎前端相關問題的十問十答張鑫旭張鑫旭大神對知乎上經典的個前端問題的回答。作者對如何避免常見的錯誤,難以發現的問題,以及性能問題和不好的實踐給出了相應的建議。但并不是本身有問題,被標準定義的是極好的。 這一次,徹底弄懂 JavaScript 執行機制 本文的目的就是要保證你徹底弄懂javascript的執行機制,如果讀完本文還不懂,可以揍我。 不論你是javascript新手還是老...
摘要:手把手教你做個人火的時候,隨便一個都能賺的盆滿缽滿,但是,個人沒有服務端,沒有美工,似乎就不能開發了,真的是這樣的嗎秘密花園經典的中文手冊。涵蓋前端知識體系知識結構圖書推薦以及入門視頻教程,全的簡直不要不要的了。 JavaScript 實現點擊按鈕復制指定區域文本 html5 的 webAPI 接口可以很輕松的使用短短的幾行代碼就實現點擊按鈕復制區域文本的功能,不需要依賴 flash。...
閱讀 2101·2023-04-25 17:23
閱讀 2919·2021-11-17 09:33
閱讀 2513·2021-08-21 14:09
閱讀 3579·2019-08-30 15:56
閱讀 2605·2019-08-30 15:54
閱讀 1623·2019-08-30 15:53
閱讀 2126·2019-08-29 13:53
閱讀 1141·2019-08-29 12:31