咖啡加点糖:javascript中该注意的几点

2016-12-30  本文已影响0人  逗逗兜豆豆

1、JavaScript允许对任意数据类型做比较

第一种是==比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;

第二种是===比较,它不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较。

由于JavaScript这个设计缺陷,不要使用==比较,始终坚持使用===比较

浮点数在运算过程中会产生误差,因为计算机无法精确表示无限循环小数。要比较两个浮点数是否相等,只能计算它们之差的绝对值,看是否小于某个阈值:

Math.abs(1/3- (1-2/3)) <0.0000001;//true

2、JavaScript的设计者希望用null表示一个空的值,而undefined表示值未定义。事实证明,这并没有什么卵用,区分两者的意义不大。大多数情况下,我们都应该用null。undefined仅仅在判断函数参数是否传递的情况下有用。

3、数组Array

3.1、直接给Array的length赋一个新的值会导致Array大小的变化,即数组的length属性是可写

如果赋一个比length大的值,数组多出的部分用undefined代替

如果通过索引赋值时,索引超过了范围,同样会引起Array大小的变化:

var arr = [1,2,3];
arr[5] ='x';
arr;// arr变为[1, 2, 3, undefined, undefined, 'x']

如果赋一个比length小的值,那么多出的部分就会被截断。(引申:如果赋0,则是清空数组)
但是需要注意一点,通过点属性的方式及 "att.属性 " 来添加内容是不会引起length长度的变化,即js中的length只用来描述索引元素的长度,忽略关联元素

3.2、对于Array,如果不给slice()传递任何参数,它就会从头到尾截取所有元素。利用这一点,我们可以很容易地浅复制一个Array:

var arr = ['A','B','C','D','E','F','G'];
var aCopy = arr.slice();
aCopy;// ['A', 'B', 'C', 'D', 'E', 'F', 'G']
aCopy === arr;// false

3.3、对于数组的concat()方法,习惯上我们认为它接收一个数组参数,其实它可以接收任意个非数组元素和Array(如果是个一维数组,则会进行一次拆分,否则不拆分),然后全部添加到新的Array里:

var arr = ['A','B','C'];
arr.concat(1,2, [3,4]);// ['A', 'B', 'C', 1, 2, 3, 4]

注意:concat对添加的数组只进行一次拆分,如果接收的Array是个多维数组,不会进行拆分

3.4、Array的sort()方法默认把所有元素先转换为String再排序,如果不知道sort()方法的默认排序规则,直接对数字排序,绝对栽进坑里!

4、对象

对象的属性访问可以通过两个方式进行:一种是"对象.属性名",一种是 对象[ '属性名' ]

如果属性名是个合常规的,上边两种方式都可以,但是如果属性名中含有特殊的字符,如“-” 或者 空格 ,则只能通过第二种方式进行访问

测试一个对象是否拥有某一属性,可以用in操作符 或者 hasOwnProperty()方法,in会搜索原型链,检索对象自己的和继承过来的属性,而hasOwnProperty()方法只会检测是否是自己的属性

5、for( item  in target)

如果target是一个对象,则item代表的是对象的属性

如果target是一个数组,由于Array也是对象,而它的每个元素的索引被视为对象的属性的一部分,所以item代表的是索引,但是如果不通过Array提供的方法(方法和初始化)向数组中添加元素,你在数组上手动添加的属性不会被认为是索引的,即length是不会发生变化的,但是遍历的时候属性包括了索引和添加上来的内容,如下

var a = ['A','B','C'];
a.name ='Hello';
for(var x in a) {
    alert(x);// '0', '1', '2', 'name'
}
a // ['A','B','C']
a.length // 3

6、方法内部有关变量的提升

JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部,只是提升声明,赋值操作是在代码执行到对应位置的时候才执行

functionfoo(){
    var x ='Hello, '+ y;
    alert(x);
    var y ='Bob';
}
等价于:
functionfoo(){
    var y;// 提升变量y的申明
    var x ='Hello, '+ y;   
    alert(x);
    y ='Bob';
}

所以在开发中,应严格遵守“在函数内部首先申明所有变量”这一规则

7、作用域

Javascript的变量范围是以函数为基础的,每个函数都有它自己的变量范围,Javascript这一点上表现的很酷,根本不理睬一些无意义的花括弧包起来的范围。

不在任何函数内定义的变量就具有全局作用域

var a = 1 等价于 window.a = 1

如果对象中定义了方法,要保证方法中this指向正确,必须用obj.xxx()的形式调用,否则this会被调用方法时调用该方法的对象改写

方法.apply(obj, [ ])、方法.call(obj, arg1, arg2, ...)可以动态改变方法中的this指向,对于普通方法的调用,我们可以使用 方法.apply(null, [ ])和 方法.call(null,arg1,arg2,...)的方式,比如调用Math.max(3, 5, 4),分别用apply()和call()实现如下:

Math.max.apply(null, [3,5,4]);// 5
Math.max.call(null,3,5,4);// 5

8、闭包

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值(即函数有一个参数来接收变量)并用“创建一个匿名函数并立刻执行”的语法将i的值传入,无论该循环变量后续如何更改,已绑定到函数参数的值不变。

闭包的实质:闭包就是携带状态的函数!携带状态的函数!是携带状态的函数!并且它的状态可以完全对外隐藏起来。!

9、包装对象

包装对象用new创建:

var n =new Number(123);// 123,生成了新的包装类型
var b =new Boolean(true);// true,生成了新的包装类型
var s =new String('str');// 'str',生成了新的包装类型

虽然包装对象看上去和原来的值一模一样,显示出来也是一模一样,但他们的类型已经变为object了!所以,包装对象和原始值用===比较会返回false!

所以闲的蛋疼也不要使用包装对象!尤其是针对string类型!!!

如果我们在使用Number、Boolean和String时,没有写new,那么Number()、Boolean()和String()被当做普通函数,把任何类型的数据转换为number、boolean和string类型(注意不是其包装类型)

所以闲的蛋疼也不要使用包装对象!尤其是针对string类型!!!

10、字符串型数值快速转变为数值类型,只需在字符串前边加上“+”
var a = '123.4' ;
var b = +a + 100 // b=223.4

11、数值快速取整:数值|0

总结一下,有这么几条规则需要遵守:
不要使用new Number()、new Boolean()、new String()创建包装对象;
用parseInt()或parseFloat()来转换任意类型到number;
用String()来转换任意类型到string,或者直接调用某个对象的toString()方法;
通常不必把任意类型转换为boolean再判断,因为可以直接写if (myVar) {...};
typeof操作符可以判断出number、boolean、string、function和undefined;
判断Array要使用Array.isArray(arr);
判断null请使用myVar === null;
判断某个全局变量是否存在用typeof window.myVar === 'undefined';
函数内部判断某个变量是否存在用typeof myVar === 'undefined'。

12、
event.currentTarget指向事件所绑定的元素,
而event.target始终指向事件发生时的元素。

上一篇下一篇

猜你喜欢

热点阅读