(三)JavaScript

1.JS Array--方法slice()和splice()

  arrayObj.slice(start,end); 此方法返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

  注意:此方法并不会修改数组,而是返回一个子数组。

  arrayObj.splice(index,howmany,item1,......,itemX); 此方法向/从数组中添加/删除项目,然后返回被删除的项目。

  注意:该方法会改变原始数组。

2.instanceof 和 typeof

  typeof 和 instanceof 常用来判断一个变量是否为空,或者是什么类型的。但它们之间还是有区别的:

  typeof返回值是一个字符串,该字符串说明运算数的类型。一般只能返回如下几个结果:

  number,boolean,string,function,object,undefined

  instanceof与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。例如:

var oStringObject = new String("hello world");
alert(oStringObject instanceof String);    //输出 "true"

  这段代码问的是“变量 oStringObject 是否为 String 对象的实例?”oStringObject 的确是 String 对象的实例,因此结果是 "true"。

3.NOT运算符

  与逻辑 OR 和逻辑 AND 运算符不同的是,逻辑 NOT 运算符返回的一定是 Boolean 值。

  逻辑 NOT 运算符的行为如下:

  • 如果运算数是对象,返回 false
  • 如果运算数是数字 0,返回 true
  • 如果运算数是 0 以外的任何数字,返回 false
  • 如果运算数是 null,返回 true
  • 如果运算数是 NaN,返回 true
  • 如果运算数是 undefined,发生错误

  js中判断变量的Boolean值时,可以直接使用NOT运算符,无论运算数是什么类型,第一个 NOT 运算符返回 Boolean 值。第二个 NOT 将对该 Boolean 值求负,从而给出变量真正的 Boolean 值。而不必用if(variable == true)这样的表达方式。

4.两套等性运算符:等号和非等号用于处理原始值,全等号和非全等号用于处理对象。

  “==”和“!=”:

  执行类型转换的规则如下:

  • 如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。
  • 如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。
  • 如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。
  • 如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。

  在比较时,该运算符还遵守下列规则:

  • 值 null 和 undefined 相等。
  • 在检查相等性时,不能把 null 和 undefined 转换成其他值。
  • 如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。
  • 如果两个运算数都是对象,那么比较的是它们的引用值。如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。

  重要提示:即使两个数都是 NaN,等号仍然返回 false,因为根据规则,NaN 不等于 NaN。

  "==="和"!==":

  这两个运算符所做的与等号和非等号相同,只是它们在检查相等性前,不执行类型转换

5.闭包

  闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。例如:

var iBaseNum = 10;

function addNum(iNum1, iNum2) {
  return  function doAdd() {
    return iNum1 + iNum2 + iBaseNum;
  }
}

  这里内部函数可以访问iNum1,iNum2。之所以可以访问这些变量,是因为内部函数的作用域链中包含addNum()的作用域。要彻底弄清楚其中的细节,必须从理解函数被调用的时候都会发生什么入手。

  而有关如何创建作用域链以及作用域链有什么作用的细节,对彻底理解闭包至关重要。当某个函数被调用时,会创建一个执行环境及相应的作用域链。然后,使用arguments和其他命名参数来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,……直至作为作用域链终点的全局执行环境。

  在另一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。因此,在addNum()函数内部定义的匿名函数的作用域链中,实际上将会包含外部函数addNum()的活动对象。

  在匿名函数从addNum()中被返回后,它的作用域链被初始化为包含addNum()函数的活动对象和全局变量对象。这样匿名函数就可以访问在addNum()中定义的所有变量。更重要的是,addNum()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。换句话说,当addNum()函数返回后,其执行环境的作用域链会被销毁,但他的活动对象仍然会留在内存中;直到匿名函数被销毁后,addNum()的活动对象才会被销毁。

 

  注意:请慎重使用闭包,因为闭包会携带包含它的函数的作用域,因此会比其他函数占据更多的内存。建议只在绝对必要的时候再考虑使用闭包。

5.继承机制--call()和apply()的用法与区别

  手册中对call方法和apply()方法的解释--调用一个对象的一个方法,以另一个对象替换当前对象。

  利用W3C里的例子,就可以清楚的了解他们的调用方式:

 1 function sayColor(sPrefix,sSuffix) {
 2     alert(sPrefix + this.color + sSuffix);
 3 };
 4 
 5 var obj = new Object();
 6 obj.color = "blue";
 7 
 8 //call()
 9 sayColor.call(obj, "The color is ", "a very nice color indeed.");
10 
11 //apply()
12 sayColor.apply(obj, new Array("The color is ", "a very nice color indeed."));

虽然apply和call两者在作用上是相同的,但两者在参数上有区别的:

对于第一个参数意义都一样,但对第二个参数:apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。

如 func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1,[var1,var2,var3])

同时使用apply的好处是--可以直接将当前函数的arguments对象作为apply的第二个参数传入。