常用的原生函数有:String()、Number()、Boolean()、Array()、Object()、Function()、RegExp()、Date()、Error()、Symbol()(ES6)
1)内部属性 [[Class]]
所有 typeof 返回值为 “object” 的对象(如数组[object Array])都包含一个内部属性 [[Class]](我们可
以把它看作一个内部的分类,而非传统的面向对象意义上的类)。这个属性无法直接访问,
一般通过 Object.prototype.toString(…) 来查看。
Object.prototype.toString.call( [1,2,3] );
// "[object Array]"
Object.prototype.toString.call( /regex-literal/i );
// "[object RegExp]"
//虽然 Null() 和 Undefined() 这样的原生构造函数并不存在,
//但是内部 [[Class]] 属性值仍然是 "Null" 和 "Undefined"。
Object.prototype.toString.call( null );
// "[object Null]"
Object.prototype.toString.call( undefined );
// "[object Undefined]"
Object.prototype.toString.call( "abc" );
// "[object String]"
Object.prototype.toString.call( 42 );
// "[object Number]"
Object.prototype.toString.call( true );
// "[object Boolean]"
2)封装对象
2.1)自动封装对象
封 装 对 象(object wrapper) 扮 演 着 十 分 重 要 的 角 色。 由 于 基 本 类 型 值 没 有 .length
和 .toString() 这样的属性和方法,需要通过封装对象才能访问,此时 JavaScript 会自动为
基本类型值包装(box 或者 wrap)一个封装对象。
var a = "abc";
a.length; // 3
a.toUpperCase(); // "ABC"
因为浏览器已经为 .length 这样的常见情况做了性能优化,直接使用封装对象来“提前优化”代码反而会降低执行效率。
因此,应该优先考虑使用 “abc” 和 42 这样的基本类型值,而非 new String(“abc”) 和 new Number(42)。
2.2)封装对象疑惑点
var a = new Boolean( false );//一个Object,实际是真值
if (!a) {// !object <==> false
console.log( "Oops" ); // 执行不到这里
}
2.3)拆分封装对象
如果想要得到封装对象中的基本类型值,可以使用 valueOf() 函数:
var a = new String( "abc" );
var b = new Number( 42 );
var c = new Boolean( true );
a.valueOf(); // "abc"
b.valueOf(); // 42
c.valueOf(); // true
3)原生函数作为构造函数
3.1)Array(…)
/**构造函数 Array(..) 不要求必须带 new 关键字。不带时,它会被自动补上。
因此 Array(1,2,3) 和 new Array(1,2,3) 的效果是一样的。**/
var a = new Array( 1, 2, 3 );
a; // [1, 2, 3]
var b = [1, 2, 3];
b; // [1, 2, 3]
/**Array.map(v,i) v-value,i-index
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意:map() 不会对空数组进行检测,会抛出异常。
map() 不会改变原始数组。
**/
b.map(function(v,i){ return i; }); // [ 0, 1, 2 ] 返回下标值
/**!!! 注意:避免创建和使用空单元数组 !!!**/
//诸如以下几种
var a = new Array( 3 );
var c = [];
c.length = 3;
//皆会产生一些难以控制的问题
3.2)Object(…)、Function(…) 和 RegExp(…)
正则表达式知识普及:
修饰符 | 描述 |
---|---|
i | 执行对大小写不敏感的匹配。 |
g | 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。 |
m | 执行多行匹配。 |
元字符 | 描述 |
---|---|
\d | 查找数字。 |
\s | 查找空白字符 |
\b | 匹配单词边界 |
\uxxx | 查找以十六进制数 xxxx 规定的 Unicode 字符 |
//尽量避免使用构造函数的方式
var c = new Object();
c.foo = "bar";
c; // { foo: "bar" }
var d = { foo: "bar" };
d; // { foo: "bar" }
var e = new Function( "a", "return a * 2;" );
var f = function(a) { return a * 2; }
function g(a) { return a * 2; }
var h = new RegExp( "^a*b+", "g" );
var i = /^a*b+/g;
h.test("ab");//true
i.test("ab");//true
//RegExp(..) 有时还是很有用的,比如动态定义正则表达式时:
var name = "Kyle";
var namePattern = new RegExp( "\\b(?:" + name + ")+\\b", "ig" );
var matches = someText.match( namePattern );
//上述情况在 JavaScript 编程中时有发生,这时 new RegExp("pattern","flags") 就能派上用场。
3.3) Date(…) 和 Error(…)
Date(…) 和 Error(…) 没有对应的基本类型形式来作为它们的替代。
Date: 创建日期对象必须使用 new Date()。如果调用 Date() 时不带 new 关键字,则会得到当前日期的字符串值。
Date(…) 可以带参数,用来指定日期和时间,而不带参数的话则使用当前的日期和时间。
Error: 构造函数 Error(…)(与 Array() 类似)带不带 new 关键字都可。
//从 ES5 开始引入了一个更简单的方法,即静态函数 Date.now()。
//对 ES5 之前的版本我们可以使用下面的 polyfill:
if (!Date.now) {
Date.now = function(){
return (new Date()).getTime();
};
}
//错误对象通常与 throw 一起使用:其他诸如ReferenceError的错误一般程序出错时由javascript引擎抛出。
function foo(x) {
if (!x) {
throw new Error( "x wasn’t provided" );
}
// ..
}
4)原生函数的原型
原生构造函数有自己的 .prototype 对象,如 Array.prototype、String.prototype 等。
String原型链上提供的方法:
• String#indexOf(…)
在字符串中找到指定子字符串的位置• String#charAt(…)
获得字符串指定位置上的字符。
• String#substr(…)、String#substring(…) 和 String#slice(…)
获得字符串的指定部分。
• String#toUpperCase() 和 String#toLowerCase()
将字符串转换为大写或小写。
• String#trim()
去掉字符串前后的空格,返回新的字符串。
以上方法并不改变原字符串的值,而是返回一个新字符串。
将原型作为默认值:
Function.prototype 是一个空函数,RegExp.prototype 是一个“空”的正则表达式(无
任何匹配),而 Array.prototype 是一个空数组。对未赋值的变量来说,它们是很好的默
认值。
function isThisCool(vals,fn,rx) {
vals = vals || Array.prototype;
fn = fn || Function.prototype;
rx = rx || RegExp.prototype;
return rx.test(
vals.map( fn ).join( "" )
);
}
isThisCool(); // true 空正则匹配空串为true
isThisCool(
["a","b","c"],
function(v){ return v.toUpperCase(); },
/D/
); // false