js方法文档
in 教程文档 with 0 comment

js方法文档

in 教程文档 with 0 comment

js方法

基础

类型

typeof 返回值有六种可能: numberstringbooleanobjectfunctionundefined

number数字类型,在内部被表示为64位的浮点数,和javadouble一样。不像大多数其他的编程语言,它没有分离出整数类型,所以1与1.0是相同的值。
还有两个特殊的数NaNInfinity

string用于处理文本(字符串),和java中的String差不多,相关方法也很像,length属性声明了该字符串中的字符数。

boolean布尔值,表示两个值:truefalse。使用Boolean()函数时,0-0null""falseundefinedNaN都为false,否则为true

object万物皆对象,JavaScript 提供多个内建对象,比如 DateArray 等等。 对象只是带有属性和方法的特殊数据类型。对象的统一空值null

function JavaScript函数,函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块,函数是对象,函数也有属性和方法。

undefined属性用于存放JavaScriptundefined值。null表示无值,而undefined表示一个未声明的变量,或已声明但没有赋值的变量,或一个并不存在的对象属性。

逻辑运算符

&& 逻辑与 a && b
如果a的布尔值为false,则跳过b,直接返回a;
如果a的布尔值为true,则返回b;
使用:

  1. 用在if判断中。
  2. 判断方法执行,例如:当传入参数有值时执行初始化方法。
    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. 用在赋值语句中,例如:当传入参数为空时设置默认值。
    var a = 0, b = 1, c;
    c = a || b;
    console.log(c); // 1
    c = b || 3;
    console.log(c); // 3
    

! 取反
任何对象取反后都会转换为布尔值,获取自己本身的布尔值时可以取反两次例如!!

==和===

== 先比较类型,类型相同则比较值,类型不同,则转换为相同类型,再比较值。
一些容易出问题的逻辑:

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

=== 既比较类型也比较值。
一些容易出问题的逻辑:

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)

返回在指定位置的字符。

str.charAt(2); // "C" 
str.charAt(10); // "" 

charCodeAt(index)

返回在指定的位置的字符的 Unicode 编码。

str.charCodeAt(2); // 67
str.charCodeAt(10); // NaN 

concat(s1, s2, ..., sn)

连接两个或更多字符串,并返回新的字符串。

str.concat('Ss', 66, true); // "ABCabcABCSs66true" 

indexOf(s)

返回某个指定的字符串值在字符串中首次出现的位置。

str.indexOf("A"); // 0 
str.indexOf("D"); // -1 

lastIndexOf(s)

从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。

str.lastIndexOf("A"); // 6 

includes(s)

查找字符串中是否包含指定的子字符串。

str.includes("ABC"); // true 
str.includes("ABCD"); // false 

match(regexp)

查找找到一个或多个正则表达式的匹配。

str.match(/A.C/g); // ["ABC", "ABC"] 

repeat(size)

复制字符串指定次数,并将它们连接在一起返回。

str.repeat(2); // "ABCabcABCABCabcABC" 

replace(s/regexp, replacer)

在字符串中查找匹配的子串,并替换与正则表达式匹配的子串。第一个参数传字符串则只替换匹配到的第一个。

str.replace(/A.C/g, ""); // "abc" 
str.replace("ABC", ""); // "abcABC" 

search(searchvalue)

查找与正则表达式相匹配的值。于indexOf()差不多,但支持正则表达式。

str.search(/[a-z]/g); // 3
str.search("ABC"); // 0 

split(separator,limit)

把一个字符串分割成字符串数组。

参数描述
separator可选。字符串或正则表达式,从该参数指定的地方分割。
limit可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。
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。
str.startsWith("ABC"); // true
str.startsWith("abc"); // false
str.startsWith("abc", 3); // true

slice(start, end)

提取字符串的片断,并在新的字符串中返回被提取的部分。

参数描述
start必须。 要抽取的片断的起始下标,第一个字符位置为 0。如果为负数,则从尾部开始截取。
end可选。 紧接着要截取的片段结尾的下标。若未指定此参数,则要提取的子串包括 start 到原字符串结尾的字符串。如果该参数是负数,那么它规定的是从字符串的尾部开始算起的位置。slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
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。如果省略该参数,那么返回的子串会一直到字符串的结尾。
str.substring(2); // "CabcABC"
str.substring(2,4); // "Ca"

substr(start, length)

在字符串中抽取从开始下标开始的指定数目的字符。

参数描述
start必需。要抽取的子串的起始下标。必须是数值。如果是负数,那么该参数声明从字符串的尾部开始算起的位置。也就是说,-1 指字符串中最后一个字符,-2 指倒数第二个字符,以此类推。
length可选。子串中的字符数。必须是数值。如果省略了该参数,那么返回从 stringObject 的开始位置到结尾的字串。
str.substr(2); // "CabcABC"
str.substr(2,4); // "Cabc"
str.substr(-2); // "BC"
str.substr(-3, 1); // "A"

toLowerCase()

用于把字符串转换为小写。

str.toLowerCase(); // "abcabcabc"

toLowerCase()

用于把字符串转换为大写。

str.toUpperCase(); // "ABCABCABC"

trim()

用于删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等。
该方法不适用于nullundefined类型。

数组

concat(array2,array3,...,arrayX)

用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

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)。如果为负值,表示倒数。
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)
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,则整个数组都会被搜索。
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。如省略该参数,则将从字符串的首字符开始检索。
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。如省略该参数,则将从字符串的最后一个字符处开始检索。
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可选。指定要使用的分隔符。如果省略该参数,则使用逗号作为分隔符。
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()

用于删除数组的第一个元素并返回删除的元素。

var arr = ["A", "B", "C"];
console.log(arr.shift()); // "A"
console.log(arr); // ["B", "C"]

pop()

用于删除数组的最后一个元素并返回删除的元素。

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可选。要添加到数组的新元素
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)

向数组的末尾添加一个或多个元素,并返回新的长度。

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)

向数组的开头添加一个或更多元素,并返回新的长度。

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()

用于反转数组中元素的顺序。

var arr = ["A", "B", "C"];
console.log(arr.reverse()); // ["C", "B", "A"]
console.log(arr); // ["C", "B", "A"]

slice(start, end)

从已有的数组中返回选定的元素。不会改变原始数组。

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可选。规定排序顺序。必须是函数。
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"
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。
该方法不会对空数组进行检测。不会改变原始数组。

参数描述同上

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)

创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
不会对空数组进行检测。不会改变原始数组。

参数描述同上

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)

返回通过测试(函数内判断)的数组的第一个元素的值。
对于空数组,函数是不会执行的。并没有改变数组的原始值。

参数描述同上

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)

返回通过测试(函数内判断)的数组的第一个元素的位置。
对于空数组,函数是不会执行的。并没有改变数组的原始值。

参数描述同上

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()本身是不支持的continuebreak语句的,continue可以使用return代替,break还是建议使用for循环语句实现。

参数描述同上

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)

返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。按照原始数组元素顺序依次处理元素。
对于空数组,函数是不会执行的。不会改变原始数组。

参数描述同上

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"
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()从数组的末尾向前将数组中的数组项做累加。

参数描述同上

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

try {
    throw new Error("抛个异常");
} catch(err) {
    console.error(err.name, err.message);
    // Error 抛个异常
} finally {
    console.log("finally");
}

静态方法

String.fromCharCode(n1, n2, ..., nX)

可接受一个或多个指定的Unicode值,然后返回一个字符串。

String.fromCharCode(72,69,76,76,79); // "HELLO"
String.fromCharCode(97); // "a"
String.fromCharCode(49); // "1"

Array.isArray(obj)

用于判断一个对象是否为数组。

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值对应的值。
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。
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);

用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象,如果属性相同,以最后一个为准。

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()的第二个参数。如果该参数被指定且不为 undefined,该传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
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属性

参数默认值描述
configurablefalse当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
enumerablefalse当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。
valueundefined该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
writablefalse当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
getundefined属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。
setundefined属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
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())。描述符具有以下键:
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 循环还会枚举原型链中的属性)。

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()返回和传入的参数相同的对象。

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)

判断一个对象是否被冻结。

// 一个对象默认是可扩展的,所以它也是非冻结的.
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)

让一个对象变的不可扩展,也就是永远不能再添加新的属性。

// 使用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)

判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。

// 新对象默认是可扩展的.
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)

封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。

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)

判断一个对象是否被密封。

// 新建的对象默认不是密封的.
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必需,目标对象内属性名称
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值作为名称的属性)组成的数组。

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]]属性的值)。

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

Object.setPrototypeOf({}, null);
Object.setPrototypeOf({}, {a: 1});

Object.is(value1, value2)

判断两个值是否为同一个值。

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)

返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和正常循环遍历该对象时返回的顺序一致 。

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循环枚举原型链中的属性)。

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)

可解析一个字符串,并返回一个浮点数。
该函数指定字符串中的首个字符是否是数字。如果是,则对字符串进行解析,直到到达数字的末端为止,然后以数字返回该数字,而不是作为字符串。

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必需。要被解析的字符串。
radix可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。
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()是一个危险的函数,它使用与调用者相同的权限执行代码,所以尽可能的不要去使用它,以防被其他人员植入恶意代码。

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 语句的字符串。
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定义函数。

函数声明

function sout(v) {
    console.log(v);
}
sout(666);

函数表达式

var sout = function (v) {
    console.log(v);
};
sout(666);

自调用函数

函数表达式可以"自调用"。
自调用表达式会自动调用。
如果表达式后面紧跟 () ,则会自动调用。
不能自调用声明的函数。
通过添加括号,来说明它是一个函数表达式:

(function () {
    console.log(666);
})();

自调用函数同样可以传参:

(function (v) {
    console.log(v);
})(666);

还可以嵌套多层调用,不过需要控制()数量,以及返回的函数数量:

(function (v) {
    console.log(v);
    return function (x) {
        console.log(x);
        return function () {
             console.log("最后一层");
        };
    };
})(666)("我是x")();

看着有点饶,其实也很好理解,就是函数的返回值还是一个函数。

箭头函数

ES6 新增了箭头函数。
箭头函数表达式的语法比普通函数表达式更简洁。

(参数1, 参数2, …, 参数N) => { 函数声明 }

(参数1, 参数2, …, 参数N) => 表达式(单一)
// 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }

当只有一个参数时,圆括号是可选的:

(单一参数) => {函数声明}
单一参数 => {函数声明}

没有参数的函数应该写成一对圆括号:

() => {函数声明}

实例:

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)

函数显式参数在函数定义时列出。

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对象包含了函数调用的参数数组。
通过这种方式你可以很方便的获取所有参数的值:

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可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为nullundefined时会自动替换为指向全局对象,原始值会被包装。
arg1, arg2, ...可选的。指定的参数列表。
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可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为nullundefined时会自动替换为指向全局对象,原始值会被包装。
argsArray可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给function函数。如果该参数的值为nullundefined,则表示不需要传入任何参数。
// 把一个数组的全部元素添加到另一个数组中
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运算符构造绑定函数,则忽略该值。当使用bindsetTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为 object。如果bind函数的参数列表为空,或者thisArgnullundefined,执行作用域的this将被视为新函数的thisArg
arg1, arg2, ...可选的。当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
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全局对象,里面的每个属性都是一个方法而已。

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

/*!
 * 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是怎么写的。

/*!
 * 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文件直接使用。

其他