JavaScript语言精粹-笔记6-方法
JavaScript包含了一套小型的可用在标准类型上的标准方法集.
Array
array.concat(item…)
concat 方法产生一个新数组, 它包含一份array的浅复制(shallow copy)并把一个或多个参数item附加在其后. 如果参数item是一个数组, 那么它的每个元素会被分别添加.
var a = ['a', 'b', 'c'];
var b = ['x', 'y', 'z'];
console.log(a.concat(b, true)); // [ 'a', 'b', 'c', 'x', 'y', 'z', true ]
array.join(separator)
join 方法用于拼接数组参数字符串, separator默认值为,
var a = ['a', 'b', 'c'];
a.push('d');
console.log(a.join()); // a,b,c,d
console.log(a.join('')); // abcd
array.pop()
pop方法移除array中的最后一个元素并返回该元素, 如果array是empty, 则返回undefined
var a = ['a', 'b', 'c'];
console.log(a.pop()); // c
console.log(a); // [ 'a', 'b' ]
pop方法的实现:
Array.method('pop', function () {
return this.splice(this.length - 1, 1)[0];
});
array.push(item…)
push 方法把一个或多个参数item附加到一个数组的尾部, 并返回这个数组的新length值
var a = ['a', 'b', 'c'];
var b = ['x', 'y', 'z'];
console.log(a.push(a, true)); // 5
console.log(a); // [ 'a', 'b', 'c', [ 'x', 'y', 'z' ], true ]
push方法的实现:
Array.method('push', function () {
this.splice.apply(
this,
[this.length, 0].concat(
Array.prototype.slice.apply(arguments)
)
);
return this.length;
});
array.reverse()
reverse方法反转array里的元素的顺序, 并返回array本身:
var a = ['a', 'b', 'c'];
var b = a.reverse();
console.log(a === b); // true
console.log(a); // ['c', 'b', 'a']
array.shift()
shift方法移除数组array中的第1个元素并返回该元素, 如果这个数组array是空的, 它会返回undefined. shift通常比pop慢很多.
var a = ['a', 'b', 'c'];
console.log(a.shift()); // a
console.log(a); // [ 'b', 'c' ]
shift方法的实现:
Array.method('shift', function () {
return this.splice(0, 1)[0];
});
array.slice(start, end)
slice方法对array中的一段做浅复制. 从array[start]复制到array[end]为止. end参数是可选的, 默认为该数组的长度array.length. 如果任何一个参数是负数, array.length会和它们相加, 试图将它们变成非负数. 如果start大于等于array.length, 得到的结果将是一个新的数组.
var a = ['a', 'b', 'c'];
console.log(a.slice(0, 1)); // a
console.log(1); // [ 'b', 'c' ]
console.log(1, 2); // [ 'b' ]
console.log(a); // [ 'a', 'b', 'c' ]
array.sort(comparefn)
sort方法对array中的内容进行排序, 内部会将元素转换为字符串再对比排序, 所以不能对数字的排序起效. 参数为传入的自定义的比较函数. 返回array本身, array已经排序.
比较函数接收两个参数, 如果第1个参数应该排在前面则返回一个负数, 如果第2个参数应该排在前面则返回一个正数.
var n = [4, 8, 15, 16, 23, 42];
var nsf = n.sort();
console.log(n === nsf); // true
console.log(n); // [ 15, 16, 23, 4, 42, 8 ]
// 可以看到结果并不符合预期, 我们传入自定义的比较函数
var nst = n.sort(function (a, b) {
return a - b;
});
console.log(nst); // [ 4, 8, 15, 16, 23, 42 ]
array.splice(start, deleteCount, item…)
splice方法从array中移除一个或多个元素, 并用新的item替换它们. 参数start是从数组array中移除元素的开始位置, 参数deleteCount是要移除的元素个数, 如果有额外参数, 那些item会插入到别移除元素的位置上, 它返回一个包含被移除元素的数组.
var a = ['a', 'b', 'c'];
console.log(a.splice(1, 1, 'ache', 'bug')); // b
console.log(a); // [ 'a', 'ache', 'bug', 'c' ]
splice方法的实现:
Array.method('splice', function (start, deleteCount) {
var max = Math.max,
min = Math.min,
delta,
element,
insertCount = max(arguments.length - 2, 0),
k = 0,
len = this.length,
new_len,
result = [],
shift_count;
start = start || 0;
if (start < 0) {
start += len;
}
start = max(min(start, len), 0);
deleteCount = max(min(typeof deleteCount === 'number' ? deleteCount : len, len - start), 0);
delta = insertCount - deleteCount;
new_len = len + delta;
while (k < deleteCount) {
element = this[start + k];
if (element !== undefined) {
result[k] = element;
}
k += 1;
}
shift_count = len - start - deleteCount;
if (delta < 0) {
k = start + insertCount;
while (shift_count) {
this[k] = this[k - delta];
k ++;
shift_count --;
}
this.length = new_len;
} else if (delta > 0) {
k = 1;
while (shift_count) {
this[new_len - k] = this[len - k];
k ++;
shift_count --;
}
this.length = new_len;
}
for (k = 0; k < insertCount; k ++) {
this[start + k] = arguments[k + 2];
}
return result;
});
array.unshift(item…)
unshift方法像push方法一样, 用于将元素插入到array的开始, 并返回array的新的length.
var a = ['a', 'b', 'c'];
console.log(a.unshift('?', '@')); // 5
console.log(a); // [ '?', '@', 'a', 'b', 'c' ]
unshift方法的实现:
Array.method('unshift', function () {
this.splice.apply(this, [0, 0].concat(Array.prototype.slice.apply(arguments)));
return this.length;
});
Function
function.apply(thisArg, argArray)
apply方法调用function, 传递一个会被绑定到this上的对象和一个可选的数组作为参数, 其实就是修改函数内部this指针的指向.
封装apply方法实现函数定义时捆绑this指向的bind方法:
Function.method('bind', function (that) {
var method = this,
slice = Array.prototype.slice,
args = slice.apply(arguments, [1]);
return function () {
return method.apply(that, args.concat(slice.apply(arguments, [0])));
}
});
var x = function () {
return this.value;
}.bind({ value: 666 });
console.log(x()); // 666
Number
number.toExponential(fractionDigits)
toExponential方法用于将number转换成一个指数形式的字符串. 可选参数fractionDigits用于控制小数点后的数字位数, 值必须在0至20之间(实际在nodeV10.16.0中验证值为0至100), 默认是15.
console.log(Math.PI.toExponential()); // 3.141592653589793e+0
console.log(Math.PI.toExponential(0)); // 3e+0
console.log(Math.PI.toExponential(2)); // 3.14e+0
console.log(Math.PI.toExponential(16)); // 3.1415926535897930e+0
number.toFixed(fractionDigits)
toFixed方法用于将number转换成一个十进制形式的字符串, 可选参数fractionDigits用于控制小数点后的数字位数, 值必须在0至20之间(实际在nodeV10.16.0中验证值为0至100), 默认为0.
console.log(Math.PI.toFixed()); // 3
console.log(Math.PI.toFixed(0)); // 3
console.log(Math.PI.toFixed(2)); // 3.14
console.log(Math.PI.toFixed(16)); // 3.1415926535897930
number.toPrecision(fractionDigits)
toPrecision方法用于将number转换成一个十进制形式的字符串, 可选参数precision用于控制数字的精度, 值必须在0至21之间(实际在nodeV10.16.0中验证值为1至100), 参数默认至多为16.
console.log(Math.PI.toPrecision()); // 3.141592653589793
console.log(Math.PI.toPrecision(2)); // 3.1
console.log(Math.PI.toPrecision(16)); // 3.141592653589793
number.toString(radix)
toString方法将number转换成一个字符串, 可选参数radix表示转换的进制数, 值必须在2至36之间, 默认为10.
console.log(Math.PI.toString()); // 3.141592653589793
console.log(Math.PI.toString(2)); // 11.001001000011111101101010100010001000010110100011
console.log(Math.PI.toString(10)); // 3.141592653589793
console.log(Math.PI.toString(16)); // 3.243f6a8885a3
Object
object.hasOwnProperty(name)
如果这个object包含一个名为name的属性, 那么hasOwnProperty方法返回true, 原型链中的同名属性是不会被检查的.
这个方法对name就是”hasOwnProperty”无效, 返回false. 这句话要特别说明, 因为个人认为hasOwnProperty属于原型链的属性, 自然是应该返回false, 就像name值为toString时也是返回false一样.
var a = { member: true };
var b = Object.create(a);
console.log(b.member); // true
console.log(a.hasOwnProperty('member')); // true
console.log(b.hasOwnProperty('member')); // false
String
string.charAt(pos)
charAt方法返回在string中pos位置处的字符. 如果pos小于0或者大于等于字符串长度string.length, 则返回空字符串.
var name = 'Curly';
console.log(name.charAt(0)); // C
charAt方法的实现:
Array.method('charAt', function (pos) {
return this.slice(pos, pos + 1);
});
string.charCodeAt(pos)
charCodeAt方法返回在string中pos位置处字符的字符码位. 如果pos小于0或者大于等于字符串长度string.length, 则返回NaN.
var name = 'Curly';
console.log(name.charCodeAt(0)); // 67
string.indexOf(searchString, position)
indexOf方法在string内查找另一个字符串searchString. 如果找到, 返回第一个匹配字符的位置, 否则返回-1. 可选参数position用于设置从string的某个指定的位置开始查找.
var text = 'Mississippi';
console.log(text.indexOf('ss')); // 2
console.log(text.indexOf('ss', 3)); // 5
console.log(text.indexOf('ss', 6)); // -1
string.search(regexp)
search方法和indexOf方法类似, 只是它接收一个正则表达式而不是字符串, 如果找到匹配则返回第一个匹配的首字符位置, 否则返回-1. 此方法会忽略标识符g, 且没有position参数.
var text = 'Mississippi';
console.log(text.search(/ss/)); // 2
string.lastIndexOf(searchString, position)
lastIndexOf方法与indexOf方法类似, 只不过它是从该字符串的末尾开始查找而不是从开头.
var text = 'Mississippi';
console.log(text.lastIndexOf('ss')); // 5
console.log(text.lastIndexOf('ss', 3)); // 2
console.log(text.lastIndexOf('ss', 6)); // 5
string.localeCompare(that)
用于比较字符串, 但书中定义模棱两可, 且实际使用没有见到, 因此直接过滤
string.match(regexp)
match方法用于字符串与正则表达式匹配, 如果正则表达式没有g标识, 则调用string.match(regexp)
结果与调用regexp.exec(string)
结果相同, 否则带g标识则会生成一个包含所有匹配(处捕获分组之外)的数组. (博主注: 这里应该是处错误, 应该是除非捕获分组之外)
var text = '<html><body bgcolor=linen><p> This is <b>bold<\/b>!<\/p><\/body><\/html>';
var tags = /[^<>]+|<(\/?)([A-Za-z]+)([^<>]*)>/g;
console.log(text.match(tags));
/*
[ '<html>',
'<body bgcolor=linen>',
'<p>',
' This is ',
'<b>',
'bold',
'</b>',
'!',
'</p>',
'</body>',
'</html>' ]
*/
string.replace(searchValue, replaceValue)
replace方法对string进行查找和替换操作, 并返回一个新的字符串. 参数searchValue可以是正则表达式或字符串, 参数replaceValue可以字符串或函数. 当replaceValue为函数时函数返回的字符串就是替换文本.
当searchValue为字符串或者不带g标识的正则表达式时, replace只会替换第一个匹配到的匹配项. 否则如果是带g标识的正则表达式, 则会替换所有, 且replaceValue配合$
做特殊处理.
$符号序列 | 替换对象 |
---|---|
$$ | $ |
$& | 整个匹配的文本 |
$number | 分组捕获的文本 |
$` | 匹配之前的文本 |
$‘ | 匹配之后的文本 |
// 当searchValue分别为字符串和正则表达式的执行结果
"mother_in_law".replace('_', '-'); // 'mother-in_law'
"mother_in_law".replace(/_/, '-'); // 'mother-in_law'
"mother_in_law".replace(/_/g, '-'); // 'mother-in-law'
// 当searchValue为正则表达式时replaceValue配合$做特殊处理
var number = '(555)666-1212';
var tags = /\((\d{3})\)/g;
console.log(number.replace(tags, "$$-")); // $-666-1212, 其实就是$字符特殊, 所以用$$表示$
console.log(number.replace(tags, "$&-")); // (555)-666-1212, 将匹配到的文本(555)与-拼接然后替换
console.log(number.replace(tags, "$1-")); // 555-666-1212, 去第一个匹配分组的匹配字符串与-拼接然后替换
console.log(number.replace(tags, "$`-")); // -666-1212, 将匹配到的之前的字符串(此处为空字符串)与-拼接然后替换
console.log(number.replace(tags, "$'-")); // 666-1212-666-1212, 将匹配到的之后的字符串(此处为666-1212)与-拼接然后替换
利用参数replaceValue为对象的特性实现entityify方法用于将字符串的特殊字符转换成html源符:
Array.method('entityify', function () {
var character = {
'<': '<',
'>': '>',
'&': '&',
'"': '"',
};
return function () {
return this.replace(/[<>&"]/g, function (c) {
return character[c];
});
};
}());
string slice(start, end)
slice方法复制string的一部分来构建一个新的字符串, 参数start表示复制的开始位置, end表示复制结束的位置, end的默认值为string.length
, 如果start或end小于0, 则它们与string.length
相加. 如想得到从位置p开始的n个字符, 我们可以用string.slice(p, p + n)
. 同类方法还有string.substring
和array.slice
var text = 'and in it he says "Any damn fool could';
console.log(text.slice(18)); // "Any damn fool could
console.log(text.slice(0, 3)); // and
console.log(text.slice(-5)); // could
console.log(text.slice(19, 32)); // Any damn fool
string.split(separator, limit)
split方法将string分割成片段来创建一个字符串数组. 可选参数limit用于限制被分割的片段的数量. separator参数可以是一个字符串或一个正则表达式.
console.log('0123456789'.split('', 5)); // [ '0', '1', '2', '3', '4' ]
console.log('192.168.1.0'.split('.')); // [ '192', '168', '1', '0' ]
console.log('|a|b|c|'.split('|')); // [ '', 'a', 'b', 'c', '' ]
console.log('last, first ,middle'.split(/\s*,\s*/)); // [ 'last', 'first', 'middle' ]
console.log('last, first ,middle'.split(/\s*(,)\s*/)); // [ 'last', ',', 'first', ',', 'middle' ]
string.substring(start, end)
substring的用法和slice方法一样, 只是它不能处理负数参数. 书中建议用slice.
string.toLowerCase()
toLowerCase方法将string中的所有字母转换成小写并返回新的字符串
string.toUpperCase()
toLowerCase方法将string中的所有字母转换成大写并返回新的字符串
string.toLocaleLowerCase() 和 string.toLocaleUpperCase()
这两个方法使用本地化的规则转换字符串的大小写, 一般用不到, 除非像土耳其语言那样的I
转换成1
String.fromCharCode(char…)
String.fromCharCode方法根据传入的的数字编码返回对应的字符串
console.log(String.fromCharCode(67, 97, 116)); // Cat
RegExp
regexp.exec(string)
exec方法是使用正则表达式的最强大(和最慢)的方法. 如果它成功匹配到字符串时, 它会返回一个数组, 数组中下标0的值为匹配到的子字符串, 下标1的值是分组1捕获的文本, 下标2的值是分组2捕获的文本, 以此类推. 如果匹配失败, 则会返回null.
如果regexp带有一个g标识, 此时查找不是从这个字符串的起始位置开始, 而是从regexp.lastIndex(初始值为0)位置开始. 如果匹配成功, regexp.lastIndex会被设置为改匹配后第一个字符的位置. 不成功的匹配会重置regexp.lastIndex的值为0.
var text = '<html><body bgcolor=linen><p> This is <b>bold<\/b>!<\/p><\/body><\/html>';
var tags = /[^<>]+|<(\/?)([A-Za-z]+)([^<>]*)>/g;
let a;
while(a = tags.exec(text)) {
console.log(a);
}
/*
[ '<html>',
'',
'html',
'',
index: 0,
input: '<html><body bgcolor=linen><p> This is <b>bold</b>!</p></body></html>',
groups: undefined ]
[ '<body bgcolor=linen>',
'',
'body',
' bgcolor=linen',
index: 6,
input: '<html><body bgcolor=linen><p> This is <b>bold</b>!</p></body></html>',
groups: undefined ]
...
[ ' This is ',
undefined,
undefined,
undefined,
index: 29,
input: '<html><body bgcolor=linen><p> This is <b>bold</b>!</p></body></html>',
groups: undefined ]
...
[ '</html>',
'/',
'html',
'',
index: 61,
input: '<html><body bgcolor=linen><p> This is <b>bold</b>!</p></body></html>',
groups: undefined ]
*/
regexp.test(string)
test方法是使用正则表达式最简单也是最快的方法, 如果匹配成功返回true, 否则返回false.
console.log(/&.+;/.test('frank & beans')); // true
test方法的实现:
RegExp.method('test', function (string) {
return this.exec(string) !== null;
});