Administrator
发布于 2021-05-31 / 1 阅读
0
0

最详细的js方法文档,描述加示例,不怕你不会

# js方法 ## 基础 ### 类型 `typeof` 返回值有六种可能: `number`、`string`、`boolean`、`object`、 `function`、`undefined`。 `number`数字类型,在内部被表示为64位的浮点数,和`java`的`double`一样。不像大多数其他的编程语言,它没有分离出整数类型,所以1与1.0是相同的值。 还有两个特殊的数`NaN`和`Infinity`。 `string`用于处理文本(字符串),和`java`中的`String`差不多,相关方法也很像,`length`属性声明了该字符串中的字符数。 `boolean`布尔值,表示两个值:`true` 或 `false`。使用Boolean()函数时,`0`、`-0`、`null`、`""`、`false`、`undefined`、`NaN`都为`false`,否则为`true`。 `object`万物皆对象,JavaScript 提供多个内建对象,比如 `Date`、`Array` 等等。 对象只是带有属性和方法的特殊数据类型。对象的统一空值`null`。 `function` `JavaScript`函数,函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块,函数是对象,函数也有属性和方法。 `undefined`属性用于存放`JavaScript`的`undefined`值。`null`表示无值,而`undefined`表示一个未声明的变量,或已声明但没有赋值的变量,或一个并不存在的对象属性。 ### 逻辑运算符 `&&` 逻辑与 `a && b` 如果a的布尔值为false,则跳过b,直接返回a; 如果a的布尔值为true,则返回b; 使用: 1. 用在if判断中。 2. 判断方法执行,例如:当传入参数有值时执行初始化方法。 ``` javaScript var a = false, b = true; function aFun() { console.log("aaa"); } a && aFun(); // 不执行方法,直接返回a的值,这里没有接收 b && aFun(); // 执行方法,打印aaa ``` `||` 逻辑或 `a || b` 如果a的布尔值为false,则返回b; 如果a的布尔值为true,则跳过b,直接返回a; 使用: 1. 用在if判断中。 2. 用在赋值语句中,例如:当传入参数为空时设置默认值。 ``` javaScript var a = 0, b = 1, c; c = a || b; console.log(c); // 1 c = b || 3; console.log(c); // 3 ``` `!` 取反 任何对象取反后都会转换为布尔值,获取自己本身的布尔值时可以取反两次例如`!!`。 ### ==和=== `==` 先比较类型,类型相同则比较值,类型不同,则转换为相同类型,再比较值。 一些容易出问题的逻辑: ``` javaScript console.log("0 == ''", 0 == ''); // true console.log("0 == '0'", 0 == '0'); // true console.log("0 == false", 0 == false); // true console.log("0 == []", 0 == []); // true console.log("0 == [0]", 0 == [0]); // true console.log("0 == ['0']", 0 == ['0']); // true console.log("1 == '1'", 1 == '1'); // true console.log("1 == true", 1 == true); // true console.log("1 == [1]", 1 == [1]); // true console.log("1 == ['1']", 1 == ['1']); // true console.log("null == undefined", null == undefined); // true ``` `===` 既比较类型也比较值。 一些容易出问题的逻辑: ``` javaScript console.log("0 === ''", 0 === ''); // false console.log("0 === '0'", 0 === '0'); // false console.log("1 === '1'", 1 === '1'); // false console.log("null === undefined", null === undefined); // false ``` ## 字符串 以下所有的`str`对象初始化都为`var str = 'ABCabcABC';`。 所有方法都不会改变原始字符串。 ### charAt(index) 返回在指定位置的字符。 ``` javaScript str.charAt(2); // "C" str.charAt(10); // "" ``` ### charCodeAt(index) 返回在指定的位置的字符的 Unicode 编码。 ``` javaScript str.charCodeAt(2); // 67 str.charCodeAt(10); // NaN ``` ### concat(s1, s2, ..., sn) 连接两个或更多字符串,并返回新的字符串。 ``` javaScript str.concat('Ss', 66, true); // "ABCabcABCSs66true" ``` ### indexOf(s) 返回某个指定的字符串值在字符串中首次出现的位置。 ``` javaScript str.indexOf("A"); // 0 str.indexOf("D"); // -1 ``` ### lastIndexOf(s) 从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。 ``` javaScript str.lastIndexOf("A"); // 6 ``` ### includes(s) 查找字符串中是否包含指定的子字符串。 ``` javaScript str.includes("ABC"); // true str.includes("ABCD"); // false ``` ### match(regexp) 查找找到一个或多个正则表达式的匹配。 ``` javaScript str.match(/A.C/g); // ["ABC", "ABC"] ``` ### repeat(size) 复制字符串指定次数,并将它们连接在一起返回。 ``` javaScript str.repeat(2); // "ABCabcABCABCabcABC" ``` ### replace(s/regexp, replacer) 在字符串中查找匹配的子串,并替换与正则表达式匹配的子串。第一个参数传字符串则只替换匹配到的第一个。 ``` javaScript str.replace(/A.C/g, ""); // "abc" str.replace("ABC", ""); // "abcABC" ``` ### search(searchvalue) 查找与正则表达式相匹配的值。于indexOf()差不多,但支持正则表达式。 ``` javaScript str.search(/[a-z]/g); // 3 str.search("ABC"); // 0 ``` ### split(separator,limit) 把一个字符串分割成字符串数组。 |参数|描述| |---|---| |separator | 可选。字符串或正则表达式,从该参数指定的地方分割。| |limit | 可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。| ``` javaScript str.split("B"); // ["A", "CabcA", "C"] str.split("B", 2); // ["A", "CabcA"] str.split(/[b,B]/g); // ["A", "Ca", "cA", "C"] ``` ### startsWith(searchvalue, start) 用于检测字符串是否以指定的子字符串开始。 |参数|描述| |---|---| |searchvalue|必需,要查找的字符串。| |start|可选,查找的开始位置,默认为 0。| ``` javaScript str.startsWith("ABC"); // true str.startsWith("abc"); // false str.startsWith("abc", 3); // true ``` ### slice(start, end) 提取字符串的片断,并在新的字符串中返回被提取的部分。 |参数|描述| |---|---| |start|必须。 要抽取的片断的起始下标,第一个字符位置为 0。如果为负数,则从尾部开始截取。| |end|可选。 紧接着要截取的片段结尾的下标。若未指定此参数,则要提取的子串包括 start 到原字符串结尾的字符串。如果该参数是负数,那么它规定的是从字符串的尾部开始算起的位置。slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。| ``` javaScript str.slice(2); // "CabcABC" str.slice(2, 4); // "Ca" str.slice(-2); // "BC" str.slice(-2, -1); // "B" str.slice(-4, 8); // "cAB" ``` ### substring(from, to) 用于提取字符串中介于两个指定下标之间的字符。 返回的子串包括**开始**处的字符,但不包括**结束**处的字符。 |参数|描述| |---|---| |from|必需。一个非负的整数,规定要提取的子串的第一个字符在 string Object 中的位置。| |to|可选。一个非负的整数,比要提取的子串的最后一个字符在 string Object 中的位置多 1。如果省略该参数,那么返回的子串会一直到字符串的结尾。| ``` javaScript str.substring(2); // "CabcABC" str.substring(2,4); // "Ca" ``` ### substr(start, length) 在字符串中抽取从**开始**下标开始的指定数目的字符。 |参数|描述| |---|---| |start|必需。要抽取的子串的起始下标。必须是数值。如果是负数,那么该参数声明从字符串的尾部开始算起的位置。也就是说,-1 指字符串中最后一个字符,-2 指倒数第二个字符,以此类推。| |length|可选。子串中的字符数。必须是数值。如果省略了该参数,那么返回从 stringObject 的开始位置到结尾的字串。| ``` javaScript str.substr(2); // "CabcABC" str.substr(2,4); // "Cabc" str.substr(-2); // "BC" str.substr(-3, 1); // "A" ``` ### toLowerCase() 用于把字符串转换为小写。 ``` javaScript str.toLowerCase(); // "abcabcabc" ``` ### toLowerCase() 用于把字符串转换为大写。 ``` javaScript str.toUpperCase(); // "ABCABCABC" ``` ### trim() 用于删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等。 该方法不适用于`null`,`undefined`类型。 ## 数组 ### concat(array2,array3,...,arrayX) 用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。 ``` javaScript var nums = [0,1,2,3]; var strs = ["a","c","c"]; var res = nums.concat(strs); console.log(res); // [0, 1, 2, 3, "a", "c", "c"] res = nums.concat(strs, ["6", "6", "6"]); console.log(res); // [0, 1, 2, 3, "a", "c", "c", "6", "6", "6"] ``` ### copyWithin(target, start, end) 用于从数组的指定位置拷贝元素到数组的另一个指定位置中。 会改变原始数组得值。 |参数|描述| |---|---| |target|必需。复制到指定目标索引位置。| |start|可选。元素复制的起始位置。| |end|可选。停止复制的索引位置 (默认为 array.length)。如果为负值,表示倒数。| ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9]; // 复制数组所有元素,从数组的第5个元素开始粘贴 console.log(nums.copyWithin(5)); // [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] nums = [0,1,2,3,4,5,6,7,8,9]; // 复制从数组下标为2往后的元素,从数组的第5个元素开始粘贴 console.log(nums.copyWithin(5, 2)); // [0, 1, 2, 3, 4, 2, 3, 4, 5, 6] nums = [0,1,2,3,4,5,6,7,8,9]; // 复制从数组下标为2到下标4的元素,从数组的第5个元素开始粘贴 console.log(nums.copyWithin(5, 2, 4)); // [0, 1, 2, 3, 4, 2, 3, 7, 8, 9] ``` ### fill(value, start, end) 用于将一个固定值替换数组的元素。 会改变原始数组。 |参数|描述| |---|---| |value|必需。填充的值。| |start|可选。开始填充位置。| |end|可选。停止填充位置 (默认为 array.length)| ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9]; nums.fill(6); console.log(nums); // [6, 6, 6, 6, 6, 6, 6, 6, 6, 6] nums.fill(8, 3); console.log(nums); // [6, 6, 6, 8, 8, 8, 8, 8, 8, 8] nums.fill("9", 3, 6); console.log(nums); // [6, 6, 6, "9", "9", "9", 8, 8, 8, 8] ``` ### includes(searchElement, fromIndex) 用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false。 |参数|描述| |---|---| |searchElement|必须。需要查找的元素值。| |fromIndex|可选。从该索引处开始查找 searchElement。如果为负值,则按升序从 array.length + fromIndex 的索引开始搜索。默认为 0。如果fromIndex 大于等于数组长度 ,则返回 false 。该数组不会被搜索。如果 fromIndex 为负值,如果计算出的索引小于 0,则整个数组都会被搜索。| ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9]; console.log(nums.includes(5)); // true console.log(nums.includes(10)); // false console.log(nums.includes(5, 3)); // true console.log(nums.includes(5, 6)); // false console.log(nums.includes(5, -5)); // true console.log(nums.includes(5, -1)); // false ``` ### indexOf(item,start) 返回数组中某个指定的元素位置。如果要检索的元素没有出现,则该方法返回 -1。 |参数|描述| |---|---| |item|必须。查找的元素。| |start|可选的整数参数。规定在数组中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。| ``` javaScript var nums = ["0","1","2","3","4","5","6","7","8","9"]; console.log(nums.indexOf("5")); // 5 console.log(nums.indexOf("10")); // -1 console.log(nums.indexOf("5", 3)); // 5 console.log(nums.indexOf("5", 6)); // -1 ``` ### lastIndexOf(item,start) 返回数组中某个指定的元素位置。从该字符串的后面向前查找。如果要检索的元素没有出现,则该方法返回 -1。 |参数|描述| |---|---| |item|必须。查找的元素。| |start| 可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的最后一个字符处开始检索。| ``` javaScript var nums = ["0","1","2","3","4","3","2","1","0"]; console.log(nums.lastIndexOf("3")); // 5 console.log(nums.lastIndexOf("5")); // -1 console.log(nums.lastIndexOf("3", 4)); // 3 console.log(nums.lastIndexOf("3", 6)); // 5 ``` ### join(separator) 用于把数组中的所有元素转换一个字符串。 |参数|描述| |---|---| |separator|可选。指定要使用的分隔符。如果省略该参数,则使用逗号作为分隔符。| ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9]; console.log(nums.join()); // "0,1,2,3,4,5,6,7,8,9" console.log(nums.join("")); // "0123456789" console.log(nums.join("|")); // "0|1|2|3|4|5|6|7|8|9" ``` ### shift() 用于删除数组的第一个元素并返回删除的元素。 ``` javaScript var arr = ["A", "B", "C"]; console.log(arr.shift()); // "A" console.log(arr); // ["B", "C"] ``` ### pop() 用于删除数组的最后一个元素并返回删除的元素。 ``` javaScript var arr = ["A", "B", "C"]; console.log(arr.pop()); // "C" console.log(arr); // ["A", "B"] ``` ### splice(index,howmany,item1,.....,itemX) 用于添加或删除数组中的元素。 |参数|描述| |---|---| |index|必需。规定从何处添加/删除元素。该参数是开始插入和(或)删除的数组元素的下标,必须是数字。| |howmany|可选。规定应该删除多少元素。必须是数字,但可以是 "0"。如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。| |item1, ..., itemX|可选。要添加到数组的新元素| ``` javaScript var arr = ["A", "B", "C", "D", "E"]; console.log(arr.splice(3)); // ["D", "E"] console.log(arr); // ["A", "B", "C"] console.log(arr.splice(1, 1)); // ["B"] console.log(arr); // ["A", "C"] console.log(arr.splice(1, 0, "X")); // [] console.log(arr); // ["A", "X", "C"] console.log(arr.splice(2, 1, "X")); // ["C"] console.log(arr); // ["A", "X", "X"] ``` ### push(item1, item2, ..., itemX) 向数组的末尾添加一个或多个元素,并返回新的长度。 ``` javaScript var arr = ["A", "B", "C"]; console.log(arr.push("D")); // 4 console.log(arr); // ["A", "B", "C", "D"] console.log(arr.push("E", 6, true)); // 7 console.log(arr); // ["A", "B", "C", "D", "E", 6, true] ``` ### unshift(item1, item2, ..., itemX) 向数组的开头添加一个或更多元素,并返回新的长度。 ``` javaScript var arr = ["A", "B", "C"]; console.log(arr.unshift("D")); // 4 console.log(arr); // ["D", "A", "B", "C"] console.log(arr.unshift("E", 6, true)); // 7 console.log(arr); // ["E", 6, true, "D", "A", "B", "C"] ``` ### reverse() 用于反转数组中元素的顺序。 ``` javaScript var arr = ["A", "B", "C"]; console.log(arr.reverse()); // ["C", "B", "A"] console.log(arr); // ["C", "B", "A"] ``` ### slice(start, end) 从已有的数组中返回选定的元素。不会改变原始数组。 ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9]; console.log(nums.slice()); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] console.log(nums.slice(5)); // [5, 6, 7, 8, 9] console.log(nums.slice(5, 8)); // [5, 6, 7] console.log(nums.slice(-3)); // [7, 8, 9] console.log(nums.slice(-3, -1)); // [7, 8] ``` ### sort(sortfunction) 用于对数组的元素进行排序。 默认排序顺序为按字母升序。 |参数|描述| |---|---| |sortfunction|可选。规定排序顺序。必须是函数。| ``` javaScript var nums = [40,100,1,5,25,10]; // 默认转换为字符串排序 nums.sort(); console.log(nums); // [1, 10, 100, 25, 40, 5] // 数字升序 nums.sort(function(a,b){ return a-b; }); console.log(nums); // [1, 5, 10, 25, 40, 100] // 数字降序 nums.sort(function(a,b){ return b-a; }); console.log(nums); // [100, 40, 25, 10, 5, 1] ```
### every(function(currentValue,index,arr), thisValue) 用于检测数组所有元素是否都符合指定条件(通过函数提供)。 如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。 如果所有元素都满足条件,则返回 true。 该方法不会对空数组进行检测。不会改变原始数组。 |参数|描述| |---|---| |function(currentValue, index,arr)|必须。函数,数组中的每个元素都会执行这个函数。
参数描述
currentValue必须。当前元素的值
index可选。当前元素的索引值
arr可选。当前元素属于的数组对象
| |thisValue|可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。如果省略了 thisValue ,"this" 的值为 "undefined"| ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9], res; // 判断数组中的数是否都大于5 res = nums.every(function(currentValue,index,arr) { return currentValue > 5; }); console.log(res); // false // 判断数组中的数是否都小于10 res = nums.every(function(currentValue,index,arr) { return currentValue < 10; }); console.log(res); // true ``` ### some(function(currentValue,index,arr), thisValue) 用于检测数组中的元素是否满足指定条件(函数提供)。 如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。 如果没有满足条件的元素,则返回false。 该方法不会对空数组进行检测。不会改变原始数组。 > [参数描述同上](#callbackFunctionDescribe) ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9], res; // 判断数组中是否存在大于5的数 res = nums.some(function(currentValue,index,arr) { return currentValue > 5; }); console.log(res); // true // 判断数组中是否存在大于10的数 res = nums.some(function(currentValue,index,arr) { return currentValue > 10; }); console.log(res); // false ``` ### filter(function(currentValue,index,arr), thisValue) 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 不会对空数组进行检测。不会改变原始数组。 > [参数描述同上](#callbackFunctionDescribe) ``` javaScript var nums = [0,1,2,2,2,3,4,2,5,0,6,7,8,9], res; // 获取数组中大于5的值 res = nums.filter(function(currentValue,index,arr) { return currentValue > 5; }); console.log(res); //  [6, 7, 8, 9] // 对数组元素进行去重 res = nums.filter(function(currentValue,index,arr) { //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素 return arr.indexOf(currentValue) === index; }); console.log(res); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ``` ### find(function(currentValue,index,arr), thisValue) 返回通过测试(函数内判断)的数组的第一个元素的值。 对于空数组,函数是不会执行的。并没有改变数组的原始值。 > [参数描述同上](#callbackFunctionDescribe) ``` javaScript var objArr = [ {id: 1, name: "A"}, {id: 2, name: "B"}, {id: 3, name: "C"} ], res; // 获取数组中name值为C的元素 res = objArr.find(function(currentValue, index, arr){ return currentValue.name === "C"; }); console.log(res); // {id: 3, name: "C"} // 获取数组中id值为大于1的元素 res = objArr.find(function(currentValue, index, arr){ return currentValue.id > 1; }); console.log(res); // {id: 2, name: "B"} ``` ### findIndex(function(currentValue,index,arr), thisValue) 返回通过测试(函数内判断)的数组的第一个元素的位置。 对于空数组,函数是不会执行的。并没有改变数组的原始值。 > [参数描述同上](#callbackFunctionDescribe) ``` javaScript var objArr = [ {id: 1, name: "A"}, {id: 2, name: "B"}, {id: 3, name: "C"} ], res; // 获取数组中name值为C的元素下标 res = objArr.findIndex(function(currentValue, index, arr){ return currentValue.name === "C"; }); console.log(res); // 2 // 获取数组中id值为大于1的元素下标 res = objArr.findIndex(function(currentValue, index, arr){ return currentValue.id > 1; }); console.log(res); // 1 ``` ### forEach(function(currentValue,index,arr), thisValue) 用于调用数组的每个元素,并将元素传递给回调函数。 对于空数组,函数是不会执行的。 `forEach()`本身是不支持的`continue`与`break`语句的,`continue`可以使用`return`代替,`break`还是建议使用`for`循环语句实现。 > [参数描述同上](#callbackFunctionDescribe) ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9], res = 0; // 获取数组中name值为C的元素下标 nums.forEach(function(currentValue, index, arr) { res += currentValue; }); console.log(res); // 45 ``` ### map(function(currentValue,index,arr), thisValue) 返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。按照原始数组元素顺序依次处理元素。 对于空数组,函数是不会执行的。不会改变原始数组。 > [参数描述同上](#callbackFunctionDescribe) ``` javaScript var objArr = [ {id: 1, name: "A"}, {id: 2, name: "B"}, {id: 3, name: "C"} ], res; // 获取对象中的id列表 res = objArr.map(function(currentValue, index, arr) { return currentValue.id; }); console.log(res); // [1, 2, 3] ``` ### reduce(function(total, currentValue, index, arr), initialValue) 接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。 该方法不会对空数组进行检测。 |参数|描述| |---|---| |function(total, currentValue, index, arr)|必须。函数,数组中的每个元素都会执行这个函数。
参数描述
total必需。初始值, 或者计算结束后的返回值。
currentValue必须。当前元素的值
index可选。当前元素的索引值
arr可选。当前元素属于的数组对象
| |thisValue|可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。如果省略了 thisValue ,"this" 的值为 "undefined"| ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9]; // 求和 var res = nums.reduce(function(total,currentValue,index,arr) { return total + currentValue; }); console.log(res); // 45 ``` ### reduceRight(function(total, currentValue, index, arr), initialValue) 该方法的功能和`reduce()`功能是一样的,不同的是`reduceRight()`从数组的末尾向前将数组中的数组项做累加。 > 参数描述同上 ``` javaScript var nums = [0,1,2,3,4,5,6,7,8,9]; // 求和 var res = nums.reduceRight(function(total,currentValue,index,arr) { return total + '' + currentValue; }); console.log(res); // 9876543210 ``` ## ERROR ``` javaScript try { throw new Error("抛个异常"); } catch(err) { console.error(err.name, err.message); // Error 抛个异常 } finally { console.log("finally"); } ``` ## 静态方法 ### String.fromCharCode(n1, n2, ..., nX) 可接受一个或多个指定的`Unicode`值,然后返回一个字符串。 ``` javaScript String.fromCharCode(72,69,76,76,79); // "HELLO" String.fromCharCode(97); // "a" String.fromCharCode(49); // "1" ``` ### Array.isArray(obj) 用于判断一个对象是否为数组。 ``` javaScript Array.isArray([]); // true Array.isArray([1,2,3]); // true Array.isArray(null); // false Array.isArray(""); // false Array.isArray({}); // false ``` ### JSON.parse(text, function(key, value)) 将`json字符串`转换为`JavaScript`对象。 |参数|描述| |---|---| |text|必需, 一个有效的 JSON 字符串。| |function(key, value)|可选,一个转换结果的函数, 将为对象的每个成员调用此函数。参数有key和value,return value;为转换后key值对应的值。| ``` javaScript var obj = JSON.parse("{\"a\":1,\"b\":2}"); console.log(obj); // {a: 1, b: 2} var obj = JSON.parse("{\"a\":1,\"b\":2}", function(key, value) { console.log("key:" + key, value); if (key) { return value + 6; } return value; }); console.log(obj); /* key:a 1 key:b 2 key: {a: 7, b: 8} {a: 7, b: 8} */ ``` ### JSON.stringify(value, function(key, value)/replacer, space) 将`JavaScript`对象转换为`json字符串`。 |参数|描述| |---|---| |value|必需, 要转换的`JavaScript`值(通常为对象或数组)。| |function(key, value)/replacer|可选,一个转换结果的函数, 将为对象的每个成员调用此函数。参数有key和value,return value;为转换后key值对应的值。| |text|可选,文本添加缩进、空格和换行符,如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格,如果 space 大于 10,则文本缩进 10 个空格。space 也可以使用非数字,如:\t。| ``` javaScript var obj = {a: 1, b: 2}, res; console.log(JSON.stringify(obj)); // {"a":1,"b":2} res = JSON.stringify(obj, function(key, value) { console.log("key:" + key, value); if (key) { return value + 10; } return value; }); console.log(res); /* key: {a: 1, b: 2} key:a 1 key:b 2 {"a":11,"b":12} */ res = JSON.stringify(obj, ["a"]); console.log(res); // {"a":7} res = JSON.stringify(obj, null, 1); console.log(res); /* { "a": 7, "b": 8 } */ res = JSON.stringify(obj, null, 8); console.log(res); /* { "a": 1, "b": 2 } */ res = JSON.stringify(obj, null, '*-* '); console.log(res); /* { *-* "a": 1, *-* "b": 2 } */ ``` ### Object.assign(target, source1, source2, ... ,sourceN); 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象,如果属性相同,以最后一个为准。 ``` javaScript var target = { a: 1, b: 2 }; var source = { b: 4, c: 5 }; var returnedTarget = Object.assign(target, source); console.log(target); // {a: 1, b: 4, c: 5} console.log(returnedTarget); // {a: 1, b: 4, c: 5} returnedTarget = Object.assign({}, {s: 666}, source); console.log(returnedTarget); // {a: 1, b: 4, c: 5} ``` ### Object.create(proto,propertiesObject) 方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。 |参数|描述| |---|---| |proto|新创建对象的原型对象。| |propertiesObject|可选。需要传入一个对象,该对象的属性类型参照[Object.defineProperties()](#objectDescriptorDesc)的第二个参数。如果该参数被指定且不为 undefined,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。| ``` javaScript var obj; // 创建一个原型为null的空对象 obj = Object.create(null); console.log(obj); // {} console.log(obj.__proto__); // undefined // 以字面量方式创建的空对象就相当于: obj = {}; obj = Object.create(Object.prototype); console.log(obj); // {} console.log(obj.__proto__); // {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} // 以{a: 66}为原型创建新对象 obj = Object.create({a: 66}); console.log(obj); // {} console.log(obj.a); // 66 console.log(obj.__proto__); // {a: 66} // 创建一个以另一个空对象为原型,且拥有一个属性p的对象 obj = Object.create({}, { p: { value: 42 } }); console.log(obj); // {p: 42} // 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的 obj.p = 24; console.log(obj.p); // 42 //创建一个可写的,可枚举的,可配置的属性p o2 = Object.create({}, { p: { value: 42, writable: true, // 当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。 enumerable: true, // enumerable 定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。 configurable: true // configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。 } }); ``` ### Object.defineProperty(obj, prop, descriptor) 直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 |参数|描述| |---|---| |obj|必需,要定义属性的对象。| |prop|必需,要定义或修改的属性的名称或 Symbol 。| |descriptor|必需,要定义或修改的属性描述符。| descriptor属性 |参数|默认值|描述| |---|---|---| |configurable|false|当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。| |enumerable|false|当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。| |value|undefined|该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。| |writable|false|当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。| |get|undefined|属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。| |set|undefined|属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。| ``` javaScript var o = {}; o.a = 1; // 等同于: Object.defineProperty(o, "a", { value: 1, writable: true, configurable: true, enumerable: true }); Object.defineProperty(o, "a", { value : 1 }); // 等同于: Object.defineProperty(o, "a", { value: 1, writable: false, configurable: false, enumerable: false }); // configurable: false 这时在修改descriptor中的值就会报错了 Object.defineProperty(o, 'a', { configurable: true }); // throws a TypeError // get/set和value/writable不能同时出现 var obj = Object.defineProperty(o, "b", { get: function() { console.log('get!'); // 这里不能直接调用 this.b 会陷入死循环 return this._b; }, set: function(value) { console.log('set!'); this._b = value; } }); ``` ### Object.defineProperties(obj, props) 在一个对象上定义新的属性或修改现有属性,并返回该对象。 |参数|描述| |---|---| |obj|必需,在其上定义或修改属性的对象。| |props|必需,要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有两种:数据描述符和访问器描述符(更多详情,请参阅[Object.defineProperty()](#objectDescriptorDesc))。描述符具有以下键:| ``` javaScript var obj = {}; Object.defineProperties(obj, { 'property1': { value: true, writable: true, configurable: true, enumerable: true }, 'property2': { value: 'Hello' } }); console.log(obj); // {property1: true, property2: "Hello"} console.log(Object.keys(obj)); // ["property1"] ``` ### Object.entries(obj) 返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。 ``` javaScript var obj = { foo: 'bar', baz: 42 }; console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ] // 会根据key值自动排序 var anObj = { 100: 'a', 2: 'b', 7: 'c' }; console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ] // getFoo是不可枚举的属性 var myObj = Object.create({}, { getFoo: { value() { return this.foo; } } }); myObj.foo = 'bar'; console.log(Object.entries(myObj)); // [ ['foo', 'bar'] ] // 非对象参数将被强制转换为对象 console.log(Object.entries('foo')); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ] // 遍历key-value var obj = { a: 5, b: 7, c: 9 }; for (var [key, value] of Object.entries(obj)) { console.log(`${key} ${value}`); // "a 5", "b 7", "c 9" } ``` ### Object.freeze(obj) 冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。`freeze()`返回和传入的参数相同的对象。 ``` javaScript var obj = { prop: function() {}, foo: 'bar' }; // 新的属性会被添加, 已存在的属性可能 // 会被修改或移除 obj.foo = 'baz'; obj.lumpy = 'woof'; delete obj.prop; // 作为参数传递的对象与返回的对象都被冻结 // 所以不必保存返回的对象(因为两个对象全等) var o = Object.freeze(obj); o === obj; // true Object.isFrozen(obj); // === true // 现在任何改变都会失效 obj.foo = 'quux'; // 静默地不做任何事 // 静默地不添加此属性 obj.quaxxor = 'the friendly duck'; // 在严格模式,如此行为将抛出 TypeErrors function fail(){ 'use strict'; obj.foo = 'sparky'; // throws a TypeError delete obj.quaxxor; // 返回true,因为quaxxor属性从来未被添加 obj.sparky = 'arf'; // throws a TypeError } fail(); // 试图通过 Object.defineProperty 更改属性 // 下面两个语句都会抛出 TypeError. Object.defineProperty(obj, 'ohai', { value: 17 }); Object.defineProperty(obj, 'foo', { value: 'eit' }); ``` ### Object.isFrozen(obj) 判断一个对象是否被冻结。 ``` javaScript // 一个对象默认是可扩展的,所以它也是非冻结的. Object.isFrozen({}); // false // 一个非空对象默认也是非冻结的. var oneProp = { p: 42 }; Object.isFrozen(oneProp) // false Object.preventExtensions(oneProp); Object.defineProperty(oneProp, "p", { writable: false }); // 变得不可写 Object.defineProperty(oneProp, "p", { configurable: false }); // 变得不可配置 Object.isFrozen(oneProp) // true // 数组为冻结的 Object.isFrozen(1); // true // 字符串为冻结的 Object.isFrozen("str"); // true Object.isFrozen(Object.freeze({})); // true ``` ### Object.preventExtensions(obj) 让一个对象变的不可扩展,也就是永远不能再添加新的属性。 ``` javaScript // 使用Object.defineProperty方法为一个不可扩展的对象添加新属性会抛出异常. var nonExtensible = { removable: true }; Object.preventExtensions(nonExtensible); Object.defineProperty(nonExtensible, "new", { value: 8675309 }); // 抛出TypeError异常 // 在严格模式中,为一个不可扩展对象的新属性赋值会抛出TypeError异常. function fail() { "use strict"; nonExtensible.newProperty = "FAIL"; // throws a TypeError } fail(); ``` ### Object.isExtensible(obj) 判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。 ``` javaScript // 新对象默认是可扩展的. var empty = {}; Object.isExtensible(empty); // true // ...可以变的不可扩展. Object.preventExtensions(empty); Object.isExtensible(empty); // false // 密封对象是不可扩展的. var sealed = Object.seal({}); Object.isExtensible(sealed); // false // 冻结对象也是不可扩展. var frozen = Object.freeze({}); Object.isExtensible(frozen); // false ``` ### Object.seal(obj) 封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。 ``` javaScript var obj = { prop: function() {}, foo: 'bar' }; var o = Object.seal(obj); o === obj; // true Object.isSealed(obj); // true // 仍然可以修改密封对象的属性值 obj.foo = 'quux'; // 但是你不能将属性重新定义成为访问器属性 Object.defineProperty(obj, 'foo', { get: function() { return 'g'; } }); // throws a TypeError // 除了属性值以外的任何变化,都会失败. obj.quaxxor = 'the friendly duck'; // 添加属性将会失败 delete obj.foo; // 删除属性将会失败 // 通过Object.defineProperty添加属性将会报错 Object.defineProperty(obj, 'ohai', { value: 17 }); // throws a TypeError Object.defineProperty(obj, 'foo', { value: 'eit' }); // 通过Object.defineProperty修改属性值 ``` ### Object.isSealed(obj) 判断一个对象是否被密封。 ``` javaScript // 新建的对象默认不是密封的. var empty = {}; Object.isSealed(empty); // false // 如果你把一个空对象变的不可扩展,则它同时也会变成个密封对象. Object.preventExtensions(empty); Object.isSealed(empty); // true var sealed = {}; Object.seal(sealed); Object.isSealed(sealed); // true // 一个密封对象同时也是不可扩展的. Object.isExtensible(sealed); // === false ``` ### Object.getOwnPropertyDescriptor(obj, prop) 指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性) |参数|描述| |---|---| |obj|必需,需要查找的目标对象| |prop|必需,目标对象内属性名称| ``` javaScript var o, d; o = { get foo() { return 17; } }; d = Object.getOwnPropertyDescriptor(o, "foo"); // d { // configurable: true, // enumerable: true, // get: /*the getter function*/, // set: undefined // } o = { bar: 42 }; d = Object.getOwnPropertyDescriptor(o, "bar"); // d { // configurable: true, // enumerable: true, // value: 42, // writable: true // } o = {}; Object.defineProperty(o, "baz", { value: 8675309, writable: false, enumerable: false }); d = Object.getOwnPropertyDescriptor(o, "baz"); // d { // value: 8675309, // writable: false, // enumerable: false, // configurable: false // } ``` ### Object.getOwnPropertyNames(obj) 返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。 ``` javaScript var arr = ["a", "b", "c"]; console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"] // 类数组对象 var obj = { 0: "a", 1: "b", 2: "c"}; console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"] // 使用Array.forEach输出属性名和属性值 Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) { console.log(val + " -> " + obj[val]); }); // 输出 // 0 -> a // 1 -> b // 2 -> c //不可枚举属性 var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; }, enumerable: false } }); my_obj.foo = 1; console.log(Object.getOwnPropertyNames(my_obj)); // ["getFoo", "foo"] ``` ### Object.getPrototypeOf(obj) 返回指定对象的原型(内部[[Prototype]]属性的值)。 ``` javaScript var proto = {}; var obj = Object.create(proto); Object.getPrototypeOf(obj) === proto; // true Object.getPrototypeOf(/a/) === RegExp.prototype; // true Object.getPrototypeOf("str") === String.prototype; // true ``` ### Object.setPrototypeOf(obj, prototype) 设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或`null`。 ``` javaScript Object.setPrototypeOf({}, null); Object.setPrototypeOf({}, {a: 1}); ``` ### Object.is(value1, value2) 判断两个值是否为同一个值。 ``` javaScript console.log(Object.is('foo', 'foo')); // true console.log(Object.is('foo', 'fo')); // false console.log(Object.is([], [])); // false var foo = { a: 1 }; var bar = foo; console.log(Object.is(foo, bar )); // true console.log(Object.is(foo, { a: 1 })); // false console.log(Object.is(null, null)); // true // 特例 console.log(Object.is(0, -0)); // false console.log(Object.is(0, +0)); // true console.log(Object.is(-0, -0)); // true console.log(Object.is(NaN, 0/0)); // true ``` ### Object.keys(obj) 返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。 ``` javaScript var arr = ['a', 'b', 'c']; console.log(Object.keys(arr)); // ['0', '1', '2'] var obj = { 0: 'a', 1: 'b', 2: 'c' }; console.log(Object.keys(obj)); // ['0', '1', '2'] var anObj = { 100: 'a', 2: 'b', 7: 'c' }; console.log(Object.keys(anObj)); // ['2', '7', '100'] var myObj = Object.create({}, { getFoo: { value: function () { return this.foo; } } }); myObj.foo = 1; console.log(Object.keys(myObj)); // ['foo'] ``` ### Object.values(obj) 返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用`for...in`循环的顺序相同(区别在于`for-in`循环枚举原型链中的属性)。 ``` javaScript var obj = { foo: 'bar', baz: 42 }; console.log(Object.values(obj)); // ['bar', 42] var obj = { 0: 'a', 1: 'b', 2: 'c' }; console.log(Object.values(obj)); // ['a', 'b', 'c'] var an_obj = { 100: 'a', 2: 'b', 7: 'c' }; console.log(Object.values(an_obj)); // ['b', 'c', 'a'] var my_obj = Object.create({}, { getFoo: { value: function() { return this.foo; } } }); my_obj.foo = 'bar'; console.log(Object.values(my_obj)); // ['bar'] console.log(Object.values('foo')); // ['f', 'o', 'o'] ``` ## 全局函数 ### encodeURI(uri) 可把字符串作为`URI`进行编码。对以下在`URI`中具有特殊含义的`ASCII`标点符号,`encodeURI()`函数是不会进行转义的:`,` `/` `?` `:` `@` `&` `=` `+` `$` `#` (可以使用`encodeURIComponent()`方法分别对特殊含义的 ASCII 标点符号进行编码。). ### encodeURIComponent(uri) 可把字符串作为 URI 组件进行编码。该方法不会对`ASCII`字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: `-` `_` `.` `!` `~` `*` `'` `(` `)` 。 ### decodeURI(uri) 可对`encodeURI()`函数编码过的`URI`进行解码。 ### decodeURIComponent(uri) 可对`encodeURIComponent()`函数编码的`URI`进行解码。 ### escape(string) 可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: `*` `@` `-` `_` `+` `.` `/`。其他所有的字符都会被转义序列替换。 ### unescape(string) 可对通过`escape()`编码的字符串进行解码。 ### isNaN(value) isNaN() 函数用于检查其参数是否是非数字值。 如果参数值为 NaN 或字符串、对象、undefined等非数字值则返回 true, 否则返回 false。 ### Number(object) 把对象的值转换为数字。 如果对象的值无法转换为数字,那么`Number()`函数返回`NaN`。 ### parseFloat(string) 可解析一个字符串,并返回一个浮点数。 该函数指定字符串中的首个字符是否是数字。如果是,则对字符串进行解析,直到到达数字的末端为止,然后以数字返回该数字,而不是作为字符串。 ``` javaScript console.log(parseFloat("10")); // 10 console.log(parseFloat("10.33")); // 10.33 console.log(parseFloat("34 45 66")); // 34 console.log(parseFloat(" 60 ")); // 60 console.log(parseFloat("40 years")); // 40 console.log(parseFloat("He was 40")); // NaN ``` ### parseInt(string, radix) 可解析一个字符串,并返回一个整数。 当参数`radix`的值为`0`,或没有设置该参数时,`parseInt()`会根据`string`来判断数字的基数。 默认数字的基数如下: - 如果 string 以 "0x" 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。 - 如果 string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。 - 如果 string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。 |参数|描述| |---|---| |string|必需。要被解析的字符串。| |radix|可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。| ``` javaScript console.log(parseInt("10")); // 10 console.log(parseInt("10.33")); // 10 console.log(parseInt("34 45 66")); // 34 console.log(parseInt(" 60 ")); // 60 console.log(parseInt("40 years")); // 40 console.log(parseInt("He was 40")); // NaN console.log(parseInt("10", 10)); // 10 console.log(parseInt("010")); // 10 console.log(parseInt("0xa")); // 10 console.log(parseInt("00001010", 2)); // 10 ``` ### String(object) 把对象的值转换为字符串 ### eval(string) 计算`JavaScript`字符串,并把它作为脚本代码来执行。 如果参数是一个表达式,`eval()`函数将执行表达式。如果参数是`Javascript语句`,eval()将执行`Javascript语句`。 > `eval()`是一个危险的函数,它使用与调用者相同的权限执行代码,所以尽可能的不要去使用它,以防被其他人员植入恶意代码。 ``` javaScript eval("console.log('666')"); // 666 eval("function print(str) { console.log(str);}"); print("哈哈哈"); // 哈哈哈 var res = eval("1 + 2 + 3"); print(res ); // 6 ``` # function ## `Function`函数对象 每个`JavaScript`函数实际上都是一个`Function`对象。运行`(function(){}).constructor === Function // true`便可以得到这个结论。 ### 构造函数 ```new Function ([arg1[, arg2[, ...argN]],] functionBody)``` |参数|描述| |---|---| |arg1, arg2, ... argN|被函数使用的参数的名称必须是合法命名的。参数名称是一个有效的JavaScript标识符的字符串,或者一个用逗号分隔的有效字符串的列表;例如“×”,“theValue”,或“a,b”。| |functionBody|一个含有包括函数定义的 JavaScript 语句的字符串。| ``` javaScript var sout = new Function("v", "console.log(v)"); sout(666); // 666 var sum = new Function('a', 'b,c', 'return a + b + c'); sout(sum(1,2,3)); // 6 ``` ## 关键字`function`定义函数。 ### 函数声明 ``` javaScript function sout(v) { console.log(v); } sout(666); ``` ### 函数表达式 ``` javaScript var sout = function (v) { console.log(v); }; sout(666); ``` ### 自调用函数 函数表达式可以"自调用"。 自调用表达式会自动调用。 如果表达式后面紧跟 () ,则会自动调用。 不能自调用声明的函数。 通过添加括号,来说明它是一个函数表达式: ``` javaScript (function () { console.log(666); })(); ``` 自调用函数同样可以传参: ``` javaScript (function (v) { console.log(v); })(666); ``` 还可以嵌套多层调用,不过需要控制`()`数量,以及返回的函数数量: ``` javaScript (function (v) { console.log(v); return function (x) { console.log(x); return function () { console.log("最后一层"); }; }; })(666)("我是x")(); ``` 看着有点饶,其实也很好理解,就是函数的返回值还是一个函数。 ### 箭头函数 ES6 新增了箭头函数。 箭头函数表达式的语法比普通函数表达式更简洁。 ``` javaScript (参数1, 参数2, …, 参数N) => { 函数声明 } (参数1, 参数2, …, 参数N) => 表达式(单一) // 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; } ``` 当只有一个参数时,圆括号是可选的: ``` javaScript (单一参数) => {函数声明} 单一参数 => {函数声明} ``` 没有参数的函数应该写成一对圆括号: ``` javaScript () => {函数声明} ``` 实例: ``` javaScript const sout = v => {console.log(v)}; sout(666); // 666 const sum = (a, b) => a + b; sout(sum(3,3)); // 6 const noParam = () => {console.log("noParam ")}; noParam(); // noParam ``` ### 参数 `JavaScript`函数定义显式参数时没有指定数据类型。 `JavaScript`函数对隐式参数没有进行类型检测。 `JavaScript`函数对隐式参数的个数没有进行检测。 参数默认值为:`undefined`。 #### 显式参数(Parameters) 函数显式参数在函数定义时列出。 ``` javaScript function sout(v) { console.log(v) } sout(666); // 666 sout(); // undefined // 如果你不想他打印undefined,而是打印空字符串可以这样,使用 || function sout(v) { v = v || ""; console.log(v) } sout(666); // 666 sout(); // // ES6 支持函数带有默认参数,可以这样写: function sout(v = "") { console.log(v) } sout(666); // 666 sout(); // ``` #### 隐式参数(Arguments) 函数隐式参数在函数调用时传递给函数真正的值。 `JavaScript`函数有个内置的对象`arguments`对象。 `argument`对象包含了函数调用的参数数组。 通过这种方式你可以很方便的获取所有参数的值: ``` javaScript function sum() { console.log("当前函数传了", arguments.length,"个参数"); var total = 0; for (var i = 0; i < arguments.length; i++) { total += arguments[i]; } return total; } console.log(sum()); // 0 console.log(sum(1,2,3,4,5,6,7,8,9)); // 45 ``` ## `function`方法 ### function.call(thisArg, arg1, arg2, ...) 使用一个指定的`this`值和单独给出的一个或多个参数来调用一个函数。 |参数|描述| |---|---| |thisArg|可选的。在`function`函数运行时使用的`this`值。请注意,`this`可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为`null`或`undefined`时会自动替换为指向全局对象,原始值会被包装。| |arg1, arg2, ...|可选的。指定的参数列表。| ``` javaScript function sout(x, y) { console.log(this.name, x, y); } var name = "全局name"; sout.call(); // 全局name undefined undefined sout.call({name: "我是name"}); // 我是name undefined undefined sout.call({name: "我是name"}, "666", 888); // 我是name 666 888 sout.call(null, "666", 888); // 全局name 666 888 ``` ### function.apply(thisArg, [argsArray]) 调用一个具有给定`this`值的函数,以及以一个数组(或类数组对象)的形式提供的参数。 `call()`方法的作用和`apply()`方法类似,区别就是`call()`方法接受的是参数列表,而`apply()`方法接受的是一个参数数组。 |参数|描述| |---|---| |thisArg|可选的。在`function`函数运行时使用的`this`值。请注意,`this`可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为`null`或`undefined`时会自动替换为指向全局对象,原始值会被包装。| |argsArray|可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给`function`函数。如果该参数的值为`null`或`undefined`,则表示不需要传入任何参数。| ``` javaScript // 把一个数组的全部元素添加到另一个数组中 var array = ['a', 'b']; array.push.apply(array, [0, 1, 2]); console.log(array); // ["a", "b", 0, 1, 2] function sum() { console.log("当前函数传了", arguments.length,"个参数"); var total = 0; for (var i = 0; i < arguments.length; i++) { total += arguments[i]; } return total; } var total = sum.apply(null, [1,2,3,4,5,6,7,8,9]); console.log(total); // 45 function sout(x, y) { console.log(this.name, x, y); } var name = "全局name"; sout.apply(); // 全局name undefined undefined sout.apply({name: "我是name"}); // 我是name undefined undefined sout.apply({name: "我是name"}, ["666", 888]); // 我是name 666 888 sout.apply(null, ["666", 888]); // 全局name 666 888 ``` ### function.bind(thisArg[, arg1[, arg2[, ...]]]) 创建一个新的函数,在`bind()`被调用时,这个新函数的`this`被指定为 `bind()`的第一个参数,而其余参数将作为新函数的参数,供调用时使用。 |参数|描述| |---|---| |thisArg|可选的。调用绑定函数时作为`this`参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用`bind`在`setTimeout`中创建一个函数(作为回调提供)时,作为`thisArg`传递的任何原始值都将转换为 `object`。如果`bind`函数的参数列表为空,或者`thisArg`是`null`或`undefined`,执行作用域的`this`将被视为新函数的`thisArg`。| |arg1, arg2, ...|可选的。当目标函数被调用时,被预置入绑定函数的参数列表中的参数。| ``` javaScript function sum() { console.log("当前函数传了", arguments.length,"个参数"); var total = 0; for (var i = 0; i < arguments.length; i++) { total += arguments[i]; } return total; } var bindSum = sum.bind(null, 1, 2, 3); console.log(bindSum()); // 6 console.log(bindSum(6)); // 12 console.log(bindSum(6, 6)); // 18 function sout(x, y) { console.log(this.name, x, y); } var name = "全局name"; sout.bind()(); // 全局name undefined undefined sout.bind({name: "我是name"})(); // 我是name undefined undefined sout.bind({name: "我是name"}, "666")("999"); // 我是name 666 999 sout.bind(null, "666", 888)("999"); // 全局name 666 888 ``` # 封装`js`对象 ## 封装最简单的对象 将以下内容放在一个js文件中,引入js文件,使用`AjaxUtil.xxx()`调用即可。 其实就是创建了一个js全局对象,里面的每个属性都是一个方法而已。 ``` javaScript const AjaxUtil = { /** * ajax请求 * @param requestPath 请求路径 * @param requestData 请求参数,默认为空 * @param requestType 请求方式("POST" 或 "GET"), 默认为 "GET" * @param callback 请求成功回调函数 */ baseAjax: function (requestPath, requestData, requestType, callback) { var load = layer.load(); $.ajax({ url: requestPath, type: requestType || 'GET', data: requestData || {}, success: function (res) { layer.close(load); if (callback) { callback(res); } }, error: function () { layer.close(load); layer.alert("系统异常", {anim: 6, icon: 5, title: '提示'}); } }); }, /** * post请求 有参数 * @param path 请求路径 * @param data 请求参数 * @param callback 请求成功回调函数 */ postByAjax: function (path, data, callback) { this.baseAjax(path, data, 'POST', callback); }, /** * post请求 有参数 并且验证是否成功 * @param path 请求路径 * @param data 请求参数 * @param callback(data, res) 请求成功回调函数 data: 返回的数据 res: 返回的所有 */ postByAjaxAndVerify: function (path, data, callback) { this.postByAjax(path, data, function (res) { if (res.code === 200) { if (callback) { callback(res.data, res); } } else { layer.alert(res.msg, {anim: 6, icon: 5, title: '提示'}); } }); }, /** * post请求 无参数 * @param path 请求路径 * @param callback 请求成功回调函数 */ noParamPostByAjax: function (path, callback) { this.postByAjax(path, {}, callback); }, /** * get请求 有参数 * @param path 请求路径 * @param data 请求参数 * @param callback 请求成功回调函数 */ getByAjax: function (path, data, callback) { this.baseAjax(path, data, 'GET', callback); } }; ``` 但是这样写是存在一些问题的,我们无法定义一些只在工具类中使用方法,所有的方法属性,都是公开的,可以直接调用的。如果执行这些代码的作用域不是`window`,那我们也不能在所有地方都可以调用的到。 ## 怎么优雅的封装一个`js`对象或插件? 这也是我一直在寻找的问题,怎么封装对象或插件是比较合理好用的呢?我也没有找到一个确切的方法。 既然找不到“参考答案”,那我们就来看看大佬们都是怎么做的,首先看看`jQuery`,以下为`jQuery`的部分源码,我么来分析一下。 ### 分析`jQuery` ``` javaScript /*! * jQuery JavaScript Library v3.6.0 * https://jquery.com/ * * Includes Sizzle.js * https://sizzlejs.com/ * * Copyright OpenJS Foundation and other contributors * Released under the MIT license * https://jquery.org/license * * Date: 2021-03-02T17:08Z */ ( function( global, factory ) { "use strict"; if ( typeof module === "object" && typeof module.exports === "object" ) { // For CommonJS and CommonJS-like environments where a proper `window` // is present, execute the factory and get jQuery. // For environments that do not have a `window` with a `document` // (such as Node.js), expose a factory as module.exports. // This accentuates the need for the creation of a real `window`. // e.g. var jQuery = require("jquery")(window); // See ticket #14549 for more info. module.exports = global.document ? factory( global, true ) : function( w ) { if ( !w.document ) { throw new Error( "jQuery requires a window with a document" ); } return factory( w ); }; } else { factory( global ); } // Pass this if window is not defined yet } )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { // Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 // throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode // arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common // enough that all such attempts are guarded in a try block. "use strict"; ... var version = "3.6.0", // Define a local copy of jQuery jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' // Need init if jQuery is called (just allow error to be thrown if not included) return new jQuery.fn.init( selector, context ); }; ... var // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$; jQuery.noConflict = function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }; // Expose jQuery and $ identifiers, even in AMD // (#7102#comment:10, https://github.com/jquery/jquery/pull/557) // and CommonJS for browser emulators (#13566) if ( typeof noGlobal === "undefined" ) { window.jQuery = window.$ = jQuery; } return jQuery; } ); ``` 大致就是定义了一个自调用函数,函数参数为当前作用域和一个初始化的函数,在自调用函数中调用了初始化的函数,初始化`jQuery`方法,也就是`$`方法,然后把该方法赋值给`window`,使得我们在所有地方都可以使用。 ### 分析`layer` 我们再看看`layer`是怎么写的。 ``` javaScript /*! * layer - 通用 Web 弹出层组件 * MIT Licensed */ ;!function(window, undefined){ "use strict"; ... //默认内置方法。 var layer = { v: '3.5.1', ie: function(){ //ie版本 var agent = navigator.userAgent.toLowerCase(); return (!!window.ActiveXObject || "ActiveXObject" in window) ? ( (agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于ie11并没有msie的标识 ) : false; }(), index: (window.layer && window.layer.v) ? 100000 : 0, path: ready.getPath, config: function(options, fn){ options = options || {}; layer.cache = ready.config = $.extend({}, ready.config, options); layer.path = ready.config.path || layer.path; typeof options.extend === 'string' && (options.extend = [options.extend]); //如果设置了路径,则加载样式 if(ready.config.path) layer.ready(); if(!options.extend) return this; isLayui ? layui.addcss('modules/layer/' + options.extend) : ready.link('theme/' + options.extend); return this; }, //主体CSS等待事件 ready: function(callback){ var cssname = 'layer', ver = '' ,path = (isLayui ? 'modules/layer/' : 'theme/') + 'default/layer.css?v='+ layer.v + ver; isLayui ? layui.addcss(path, callback, cssname) : ready.link(path, callback, cssname); return this; }, //各种快捷引用 alert: function(content, options, yes){ var type = typeof options === 'function'; if(type) yes = options; return layer.open($.extend({ content: content, yes: yes }, type ? {} : options)); }, confirm: function(content, options, yes, cancel){ var type = typeof options === 'function'; if(type){ cancel = yes; yes = options; } return layer.open($.extend({ content: content, btn: ready.btn, yes: yes, btn2: cancel }, type ? {} : options)); }, msg: function(content, options, end){ //最常用提示层 var type = typeof options === 'function', rskin = ready.config.skin; var skin = (rskin ? rskin + ' ' + rskin + '-msg' : '')||'layui-layer-msg'; var anim = doms.anim.length - 1; if(type) end = options; return layer.open($.extend({ content: content, time: 3000, shade: false, skin: skin, title: false, closeBtn: false, btn: false, resize: false, end: end }, (type && !ready.config.skin) ? { skin: skin + ' layui-layer-hui', anim: anim } : function(){ options = options || {}; if(options.icon === -1 || options.icon === undefined && !ready.config.skin){ options.skin = skin + ' ' + (options.skin||'layui-layer-hui'); } return options; }())); }, load: function(icon, options){ return layer.open($.extend({ type: 3, icon: icon || 0, resize: false, shade: 0.01 }, options)); }, tips: function(content, follow, options){ return layer.open($.extend({ type: 4, content: [content, follow], closeBtn: false, time: 3000, shade: false, resize: false, fixed: false, maxWidth: 260 }, options)); } }; ... /** 内置成员 */ window.layer = layer; ... }(window); ``` 大致就是定义了一个自调用函数,函数参数为`window`,在函数中初始化`layer`对象,并把`layer`对象赋值给`window`,使得我们在所有地方都可以使用。 ### 总结一下 1. 都是定义一个自调用函数,不需要显示的调用,引入即执行。 2. 在自调用函数中初始化要是用的对象或方法。 3. 将初始化好的对象或方法赋值给`window`,让其全局可用。 4. 放在一个`js文件`中,可对js内容进行压缩处理。 5. 页面引入`js文件`直接使用。 # 其他 - [`String`对象参考文档](https://www.runoob.com/jsref/jsref-obj-string.html) - [`Array`对象参考文档](https://www.runoob.com/jsref/jsref-obj-array.html) - [`Error`对象参考文档](https://www.runoob.com/js/js-errors.html) - [`Object`对象静态方法参考文档](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object) - [全局函数参考文档](https://www.runoob.com/jsref/jsref-obj-global.html) - [`jQuery`下载](https://jquery.com/download/) - [`layer`文档](http://layui.itmtr.cn/)

评论