一个常见的错误是在须使用数组时使用了对象,在须使用对象时使用了数组。其实规则很简单:当属性名是小而连续的整数时,用数组,否则就用对象。
JavaScript中数组 typeof 返回是 object,这并不能区分数组和对象。
var is_array = function(value){ return value && typeof value === 'object' && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')) }
首先,我们判断这个值是否为真,我们不接受 null 和其他为假的值。
其次,我们判断这个值的 typeof 运算结果是否是 object 。对于对象、数组和null来说,将得到 true。
第三,我们判断这个值是否有一个值为数字的 length 属性,对于数组是 true ,对于对象则为 false
第四,判断这个值是否包含一个 splice 方法。对于数组,返回 true
最后,我们判断 length 属性是否是可枚举的
这真的很复杂,实际上,我一直是这样用的,什么类型都能检测,堪称万能:
var toString = Object.prototype.toString function isObject(obj) { return toString.call(obj) === "[object Object]" } function isString(obj) { return toString.call(obj) === "[object String]" } function isArray(obj) { return toString.call(obj) === "[object Array]" } function isFunction(obj) { return toString.call(obj) === "[object Function]" }
五、方法
Array
concat(item...)
返回一个新数组,并不会修改原数组
var a1 = [2,3] var a2 = [332,12] console.log( a1.concat(a2) ); //[ 2, 3, 332, 12 ]
join(separator)
把一个 array 构造成一个字符串,并用 separator 作为分隔符把它们连接在一起。
pop(item...)
移除数组中最后一个元素并返回该元素
push(item...)
将一个或多个元素添加到数组尾部,会修改原数组
reverse()
反转数组中元素的顺序,会修改原数组,返回当前数组
shift()
移除数组中第一个元素
slice(start,end)
从start开始,到end为止(不包括end,可选,默认值是length)复制数组
sort(comparefn)
对数组中的内容排序,并不能给数字排序,因为默认比较函数是假定要被排序的元素都是字符串。
比较函数接受两个参数,并且如果两个参数相等返回0,如果第一个参数应该排在前面,则返回一个负数,如果第二个参数应该排在前面,则返回一个正数。
// a 比 b小时返回 -1,而且根据上述规则 a 会排在前面 // 所以这是从小到大的排序 var arr = [1,123,341,34,123] arr.sort(function(a,b){ if(a==b){ return 0 }else{ return a < b ? -1 : 1 } })
splice(start,deleteCount,item...)
splice 从数组中移除一个或多个元素,并用新的item代替他们。
start是从数组中移除元素的开始位置,deleteCount是要移除的个数。
会修改原数组,返回一个包含被移除元素的数组。
var arr = [23,3,23,2] var b = arr.splice(0,1) console.log(arr) ; //[ 3, 23, 2 ] console.log(b) ; //[ 23 ]
deleteCount 为0时,则为添加新元素:
var arr = [23,3,23,2] var b = arr.splice(1,0,'aa') console.log(arr) // [ 23, 'aa', 3, 23, 2 ] console.log(b) // []
deleteCount 与 item的个数相等时,则为替换:
var arr = [23,3,23,2] var b = arr.splice(1,1,'aa') console.log(arr) //[ 23, 'aa', 23, 2 ] console.log(b) //[ 3 ]
unshift(item...)
将item从数组头部插入数组
Function
apply(thisArg,argArray)
见 『Apply/Call调用模式』
Number
toFixed(fractionDigits)
把这个 number 转换成一个十进制形式的字符串。可选参数 fractionDigits 控制其小数点后的数字位数。
Math.PI.toFixed(); //3 Math.PI.toFixed(2); //3.14 Math.PI.toFixed(4); //3.1415
toPrecision(precision)
同 toFixed ,参数控制有效数字的位数
toString()
将number转换成字符串
Object
hasOwnProperty(name)
只检查此对象中的属性,原型链中得同名属性不会被检查。如果存在此属性则返回 true。
String
charAt(pos)
返回在字符串中pos处的字符
charCodeAt(pos)
返回不是一个字符串,而是以整数形式表示的字符码位
concat(string...)
与其他字符串连接起来构造一个新字符串,不常用,因为 + 也能满足需求
indexOf(searchString,pos)
在字符串内查找另一个字符串 searchString,如果被找到,则返回第一个匹配字符的位置,否则返回 -1 。
可选参数 pos 设置从字符串的某个指定位置开始查找。
lastIndexOf(searchString,pos)
与indexOf类似,不同从末尾开始查找
slice(start,end)
复制字符串的一部分构造一个新的字符串
split(separator,limit)
把字符串分割成片段创建数组,limit可限制被分割的片段数量。
一个有意思的技巧:
new Array(11).join('0').split('') //生成10个元素为0的数组
toLowerCase()
将字符串中所有字母转化为小写
toUpperCase()
将字符串中所有字母转化为大写
六、糟粕
这一部分用来吐槽JS这门语言设计上不周到的地方
全局变量
共三种方法定义全局变量:
脱离任何函数var语句 var foo = value
直接添加一个属性到全局对象中,全局对象是所有全局变量的容器。在web中,全局对象是 window : window.foo = value
使用未声明的变量,这被称为隐式的全局变量:foo = value
之前说过,可以通过 创建一个全局变量 和 闭包 减少全局变量污染(注意,只是减少,没办法避免,总要有暴露出来的变量,不要钻牛角尖)。
作用域
没有块级作用域,只有函数作用域
自动插入分号
JavaScript 有一个机制,会试图通过自动插入分号来修正有缺损的程序。它有可能会掩盖更为严重的错误。
return { status: true }
看起来是返回一个对象,但是自动插入分号让它返回了undefined,这样可以避免:
return { status: true }
typeof
typeof并不能正确地检测数据类型:
typeof null ; //object
所以使用 Object.prototype.toString.call(null) 这个办法就好,万能的!