IE 与 Firefox 兼容问题

Javascript中的常见问题 

1. 集合类对象问题  
现有代码中许多集合类对象取用时使用 (),IE 能接受,Firefox 不能。 
解决方法:改用 [] 作为下标运算。如:document.forms("formName") 改为 
Js代码  
  1. document.forms["formName"];  
  2. //又如:  
  3. document.getElementsByName("inputName")(1);  
  4. //改为  
  5. document.getElementsByName("inputName")[1];  


2. DIV对象  
在 IE 中,DIV对象可以使用ID作为对象变量名直接使用。在 Firefox 中不能。 
DivId.style.display = "none"; 
解决方法:document.getElementById("DivId").style.display = "none"; 
ps:得对象的方法不管是不是DIV对象,都应该使用getElementById方法。 


3. 关于frame  
现有问题:在 IE中 可以用window.testFrame取得该frame,mf中不行 
解决方法:在frame的使用方面Firefox和IE的最主要的区别是: 
如果在frame标签中书写了以下属性: 
那么IE可以通过id或者name访问这个frame对应的window对象 
而mf只可以通过name来访问这个frame对应的window对象 
例如如果上述frame标签写在最上层的window里面的htm里面,那么可以这样访问 
IE: window.top.frameId或者window.top.frameName来访问这个window对象 
Firefox:只能这样window.top.frameName来访问这个window对象 
另外,在mf和ie中都可以使用window.top.document.getElementById("frameId")来访问frame标签 
并且可以通过window.top.document.getElementById("testFrame").src = 'xx.htm'来切换frame的内容 
也都可以通过window.top.frameName.location = 'xx.htm'来切换frame的内容 


4. 窗口  
现有问题:IE中可以通过showModalDialog和showModelessDialog打开模态和非模态窗口,但是Firefox不支持。 
解决办法:直接使用window.open(pageURL,name,parameters)方式打开新窗口。 
如果需要传递参数,可以使用frame或者iframe。 


5. 在JS中定义各种对象变量名时,尽量使用id,避免使用name.  
在 IE 中,HTML 对象的 ID 可以作为 document 的下属对象变量名直接使用。在 Firefox 中不能,所以在平常使用时请尽量使用id,避免只使用name,而不使用id。 


6. document.all  
Firefox可以兼容document.all, 但会生成一条警告。可以用getElementById("*") 或者 getElementByTagName("*)来代替 
不过对于document.all.length等属性,则完全不兼容。大家尽量不要使用document.all属性. 


7. parentElement  
IE中支持使用parentElement和parentNode获取父节点. 
而Firefox只可以使用parentNode. 


8. event  
W3C不支持windows.event 
比方说,在IE里面: 
Js代码  
  1. function onMenuClick(){  
  2.     collapseMenu(event.srcElement);  
  3. }  

工作正常。不过在Firefox中,则改成: 
Js代码  
  1. function onMenuClick(evt){  
  2.     if(evt == null)  
  3.     evt = window.event; // For IE  
  4.     var srcElement = evt.srcElement? evt.srcElement : evt.target;  
  5.     // IE使用srcElement, 而Firefox使用target  
  6.     collapseMenu(srcElement);  


9. event.x 与 event.y 问题  
在IE 中,event 对象有 x, y 属性,Firefox中没有。 
解决方法: 
在Firefox中,与event.x 等效的是 event.pageX。但event.pageX IE中没有。 
故采用 event.clientX 代替 event.x。在IE 中也有这个变量。 
event.clientX 与 event.pageX 有微妙的差别(当整个页面有滚动条的时候), 
不过大多数时候是等效的。 
如果要完全一样,可以稍麻烦些: 
Js代码  
  1. mX = event.x ? event.x : event.pageX;  
然后用 mX 代替 event.x 


10. 用idName字符串取得对象的问题  
在IE中,利用 eval(idName) 可以取得 id 为 idName 的 HTML 对象,在Firefox中不能。 
解决办法:用 getElementById(idName) 代替 eval(idName). 


14. nodeName 和 tagName 问题  
在Firefox中,所有节点均有 nodeName 值,但 textNode 没有 tagName 值。 
在IE中nodeName 的使用有时会有问题。 
解决方法: 
使用 tagName,但应检测其是否为空。 


15. input的type属性  
IE下 input.type属性为只读,但是Firefox下可以修改. 


16. 自定义属性  
在mf中,自己定义的属性必须getAttribute()取得 
而IE可以直接通过"."运算符获取. 


17.const 问题  
在 IE 中不能使用 const 关键字。如 
const constVar = 32; 
在IE中这是语法错误. 
解决方法: 
不使用 const ,以 var 代替. 


18. body 对象  
Firefox的body在body标签没有被浏览器完全读入之前就存在,而IE则必须在body完全被读入之后才存在. 


19. img对象alt和title的解析  
alt:当照片不存在或者load错误时的提示, 
title:照片的tip说明, 
在IE中如果没有定义title,alt也可以作为img的tip使用,但是在Firefox中,两者完全按照标准中的定义使用 
在定义img对象时,最好将alt和title对象都写全,保证在各种浏览器中都能正常使用 


20.childNodes获取的节点  
childNodes的下标的含义在IE和Firefox中不同,Firefox使用DOM规范,childNodes中会插入空白文本节点。 
获取子节点时,一般可以通过node.getElementsByTagName()来回避这个问题。 


21.removeNode()  
Firefox中节点没有removeNode方法,必须使用如下方法 
Js代码  
  1. node.parentNode.removeChild(node);  


22.innerText  
IE支持,FIREFOX不支持 
FF中设置内容文本是用textConent属性. 

23. XMLHTTP的区别  
FireFox中的创建方法为: 
Js代码  
  1. xmlhttp=new XMLHttpRequest()  

而在IE中为: 
Js代码  
  1. xmlhttp=new ActiveXObject(”Microsoft.XMLHTTP”)  


24. img的src刷新问题  
在IE 下可以用 可以刷新图片,但在FireFox下不行。主要是缓存问题,在地址后面加个随机数就解决了: 
Js代码  
  1. myImg.src=this.src+’?'+Math.random();  


25. setAttribute()设置属性问题  
IE中很多属性都不能用setAttribute进行设置,但Firefox中却可以,如:
Js代码  
  1. theDiv.setAttribute('style','color:red');  
  2. //改为:  
  3. object.style.cssText = 'color:red;';  
  4.   
  5.   
  6. setAttribute('class','styleClass')  
  7. //改为:  
  8. setAttribute('className','styleClass');  
  9.   
  10.   
  11. obj.setAttribute('onclick','funcitonname();');  
  12. //改为:  
  13. obj.οnclick=function(){fucntionname();};  


...等等 

----------------------------------------------------------------------------------------- 

IE和FIREFOX在解析CSS方面的区别  

1. 对高度的解析  
IE:将根据内容的高度变化,包括未定义高度的图片内容,即使定义了高度,当内容超过高度时,将使用实际高度 
Firefox:没有定义高度时,如果内容中包括了图片内容,Firefox的高度解析是根据印刷标准,这样就会造成和实际内容高度不符合的情况;当定义了高度,但是内容超过高度时,内容会超出定义的高度,但是区域使用的样式不会变化,造成样式错位。 
结论:大家在可以确定内容高度的情况下最好定义高度,如果真的没有办法定义高度,最好不用使用边框样式,否则样式肯定会出现混乱! 


3.布局问题  
当你在写css的时候,特别是用float: left(或right)排列一窜图片时,会发现在firefox里面正常而IE里面有问题。无论你用margin:0,还是border: 0来约束,都无济于事。 
其实这里还有另外一个问题,就是IE对于空格的处理,firefox是忽略的而IE对于块与块之间的空格是处理的。也就是说一个div结束后要紧接着一个div写,中间不要有回车或者空格。不然也许会有问题,比如3px的偏差,而且这个原因很难发现。 
非常不走运的是我又碰到了这样的问题,多个img标签连着,然后定义的float: left,希望这些图片可以连起来。但是结果在firefox里面正常而IE里面显示的每个img都相隔了3px。我把标签之间的空格都删除都没有作用。 
后来的解决方法是在img外面套li,并且对li定义margin: 0,这样就解决了IE和firefox的显示偏差。IE对于一些模型的解释会产生很多错误问题,只有多多尝试才能发现原因。 
这只是一些简单的区别,在做布局和CSS设计时候可以综合考虑,但最为有效与简单的解决兼容问题还是用TABLE表格,表格在兼容性方面有着不错的表现. 


4.鼠标样式  
firefox不支持hand,但ie支持pointer 
解决方法: 统一使用pointer 

5. padding 问题  
padding 5px 4px 3px 1px FireFox无法解释简写, 
必须改成 padding-top:5px; padding-right:4px; padding-bottom:3px; padding-left:1px; 

6. 消除ul、ol等列表的缩进  
消除ul、ol等列表的缩进样式应写成:list-style:none;margin:0px;padding:0px; 
其中margin属性对IE有效,padding属性对FireFox有效 

7. CSS透明  
IE:filter:progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=60)。 
FF:opacity:0.6。 

8. CSS圆角  
IE:不支持圆角。 
FF: -moz-border-radius:4px,或者 
-moz-border-radius-topleft:4px; 
-moz-border-radius-topright:4px; 
-moz-border-radius-bottomleft:4px; 
-moz-border-radius- bottomright:4px;。 

9. CSS双线凹凸边框  
IE:border:2px outset;。 
FF: 
-moz-border-top-colors: #d4d0c8 white; 
-moz-border-left-colors: #d4d0c8 white; 
-moz-border-right-colors:#404040 #808080
-moz-border-bottom-colors:#404040 #808080

10. 滤镜  
IE中支持使用滤镜,而Firefox中不支持. 

11. 禁止选取网页内容:  
在IE中一般用js:obj.onselectstart=function(){return false;}; 
而firefox用CSS:-moz-user-select:none; 
 
JavaScript高级程序设计(第3版)
*  如果在函数中使用var 定义变量,那么变量在函数退出后就会被销毁
* 5种基本数据类型:Undefined、Null、Boolean、Number、String。
* 1种复杂数据类型:Object [Object本质上是由一组无序的名值对组成的]
*  ECMAScript不支持任何创建自定义类型的机制,而所有值最终都将是上述6种数据类型之一。
 
*  typeof操作符(而不是函数,所以可以不用圆括号)的 返回值:
      "undefined" ------ 如果这个值     未定义
      "boolean"    ------ 如果这个值是 布尔值
      "string"        ------ 如果这个值是 字符串
      "number"     ------ 如果这个值是 数值
      "object"        ------ 如果这个值是 对象或null
      "function"     ------ 如果这个值是 函数
*  对未经声明的变量调用delete不会导致错误,但没什么实际意义,且在严格模式下确实会导致错误。
   注:即便未初始化的变量会自动被赋予undefined值,但显式地初始化变量依然是明智的选择。如果能够做到这一点,那么当typeof操作符返回"undefined"值时,我们就知道被检测的变量还没有被声明,而不是尚未初始化
* Null 类型
   Null类型 的值是 null。 从逻辑角度来看,null值表示一个空对象指针,而这也正是使用typeof操作符检测null值时会返回"object"的原因。如:var car = null; alert(typeof car); => "object"
   如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值。这样一来,只要直接检查nll值就可以知道相应的变量是否已经保存了一个对象的引用,如: i
    f(car !=null ){ //对car对象执行操作 }
实际上,undefined值是派生自null值的, 因此ECMA-262规定对它们的相等性测试要返回true:
    alert( null == undefined ); // true
*  Boolean类型的字面值 true 和 false 是区分大小写的。也就是说,True 和 False 都不是Boolean值,只是标识符。
    将一个值转换为其对应的Boolean值,可调用转型函数Boolean(),如下所示:
        var message = "Hello world!";
        var messageAsBoolean = Boolean(message);
    在上例中,字符串message被转换成一个Boolean值,该值被保存在messageAsBoolean变量中。可以对任何数据类型的值调用Boolean()函数,而且总会返回一个Boolean值。至于返回的这个值是true还是false,取决于要转换值的数据类型及其实际值。
        数据类型                      转换为true的值                              转换为false的值
        Boolean                           true                                               false
        String                               任何非空字符串                             "" (空字符值)
        Number                            任何非零数字值(包括无穷大)         0 和 NaN
        Object                             任何对象                                         null
        Undefined                       n/a(not applicable - 不适用)            undefined
    var floatNum1 = 1. ;    //小数点后面没有数字 --- 解析为 1   [如果小数点后面没有跟任何数字-->整数保存,如本身表示为一个整数-->整数
    var floatNum2 = 10.0;  // 整数 --- 解析为10
    var floatNum  = 3.125e7;   //等于31250000   这只是一种表示变量floatNum的形式--简洁,但它的实际值则是31250000。3.125*10的7次幂
    注:浮点数值的最高精度是17位小数,但在进行算术计算时其精确度远远不如整数。例如,0.1 + 0.2 != 0.3,而是0.30000000000000004
           如,if( a+b == 0.3 ) alert("You got 0.3.");  //不要做这样的测试!
*  数值范围
    由于内存的限制,能够表示的最小数值保存在 Number.MIN_VALUE (是5e-324);
    最大数值保存在Number.MAX_VALUE中(是1.7976931348623157e+308)。
    如果超出JS数值范围那么将被自动转换成特殊的Infinity值。原为负转换成 -Infinity(负无穷), 原为正数转换成 Infinity(正无穷)。
    如果想判断一个数值是不是有穷的,即是不是位于最小 和 最大的数值之间,可用 isFinite() 函数判断。
    
*  NaN (Not a Number -- 非数值), 任何数值除以0都会导致错误,从而停止代码执行。在JS中,任何数值除以0会返回NaN,因此不会影响其他代码的执行。 a. 任何涉及NaN的操作(如NaN/10)都会返回NaN;b. NaN与任何值都不相等,包括NaN本身。如 NaN==NaN  --> false
   isNaN( 任何类型 ) 如:
      isNaN(NaN) --> true
      isNaN(10)   --> false
      isNaN("10") --> false (可以被转换成数值10)
      isNaN(true) --> false (可以被转换成数值1)
   3个函数可把非数值 转换为 数值: Number()、parseInt()、parseFloat()。
     Number()函数可用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这3个函数对于同样的输入会有返回不同的结果。
     Number()函数的转换规则如下:
        如果是Boolean值,true --> 1   /  false ---> 0
        如果是数字值,只是简单的传入和返回。
        如果是null值,返回 0.
        如果是undefined, 返回NaN
        如果是 字符串,遵循下列规则:
              如字符串中包含数字,则转换为 十进制数值。即"1"-->1,  "123"-->123,  "011" --> 11;
              如字符串中包含 有效的浮点格式,如"1.1"--> 1.1 ,  "01.01" --> 1.01;
              如字符串中包含 有效的十六进制格式,例如"0xf", 则将其转换为相同大小的十进制整数值;
              如 "" , 则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,然后再次依照前面的规则转换返回的字符串值。
         e.g.  Number("Hello word!") --> NaN
                 Number("")                  -->  0
                 Number("000011")      --> 11
                 Number(true)              -->  1
 
         e.g.  parseInt("1234blue")   --> 1234
                 parseInt("")                  --> NaN
                 parseInt("0xA")            --> 10 (十六进制数)
                 parseInt(22.5)             --> 22
                 parseInt("070")            --> 56 (八进制数)
                 parseInt("70")              --> 70
                 parseInt("0xf")              --> 15 (十六进制数)
     注:ECMAScript 3 JavaScript引擎中,"070" 被当成八进制字面量,因此转换后的值是 十进制的56。而在ECMAScript 5 JavaScript引擎中,parseInt()会认为无效,从而将这个值当成"0",结果就得到十进制的0。所以用到了 parseInt()的第二个参数 parseInt("070",8), parseInt("0xAF",16) --> 175,   parseInt("AF",16) --> 175,   parseInt("AF") --> NaN
            如果忽略parseInt的第二个参数,那么数字的基数将由下面的规则所决定:
           ◆ 默认基数为10,即按10进制解析
           ◆ 如果数字以0x开头,那么基数为16,即按16进制解析
           ◆ 如果数字以0开头,那么基数为8,即按8进制解析
     
     parseFloat() 从第一个字符开始解析每个字符。而且也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数字字符为止。也就是说,字符串中的第一个小数点是有效的,而第二个小数点是无效的,它后面的字符串将被忽略。如: "22.34.5"--> 22.34
     parseFloat()始终都会忽略前导的零。 注:十六进制格式的字符串则始终会被转换成0。由于它只解析十进制值,因此它没有用第二个参数指定基数的用法,如果字符串包含的是一个可解析为整数的数,parseFloat()会返回整数。
     var num1 = parseFloat("1234blue");  //1234
     var num2 = parseFloat("0xA");         //0
     var num3 = parseFloat("22.34.5");   //22.34
     var num4 = parseFloat("0908.5");     //908.5
     var num5 = parseFloat("3.125e7");   // 31250000
 
* String类型用于表示 由0 或 多个16位 Unicode字符组成的字符序列,即字符串。
   数值、布尔值、对象、字符串值都有toString()方法,但null 和 undefined 值没有此方法。一般调用toStrng()方法不必传递参数,但在调用数值的toString()方法时,可以传递一个参数:输出数值的基数。默认情况下,toString()方法以十进制格式返回数值的字符串表示。而通过传递基数,toString()可输出以二、八、十六进制,乃至其他任意有效进制格式表示的字符串值。如下:
     var num = 10;
     alert( num.toString() );      //"10"
     alert( num.toString(2));     //"1010";
     alert( num.toString(8));     //"12"
     alert( num.toString(10));   //"10"
     alert( num.toString(16));   //"a"
     //在不知道要转换的值是不是null或undefined的情况下,还可以使用转型函数String(),此函数能够将任何类型的值转换为字符串。
     var value3 = null;
     var value4;
     alert( String(value3) );    //"null"
     alert( String(value4) );    //"undefined"
 
* Object类型 是一组数据和功能的集合。
   var o = new Object;  //有效,但不推荐省略圆括号
   在ECMAScript中Object类型是所有他的实例的基础。换句话说,Object类型所具有的任何属性和方法也同样存在于更具体的对象中。
   Object的每个实例都具有下列属性和方法:
     ◆ Constructor: 保存着用于创建当前对象的函数。对于前面的例子而言,构造函数(contructor)就是Object().
     ◆ hasOwnProperty(propertyName): 用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定。如:o.hasOwnProperty("name").  hasOwnProperty是用来判断一个对象是否有你给出名称的属性或对象。不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。
        e.g. 1
        function Test( name1, name2 ){
             this.name1 = name1;
             this.name2 = name2;
        }
        Test.prototype.showName1 = function(){ ... };
        Test.prototype.showName2 = function(siteUrl){ this.siteUrl = siteUrl; };
        var n1 = new Test("peng","tao");
        var n2 = new Test("henry","pt");
        n1.age = "30";
        alert( n1.hasOwnProperty("name1")); //true
        alert( n1.hasOwnProperty("age"));     //true
        alert( n1.hasOwnProperty("showName1")); //false
        alert( n1.hasOwnProperty("siteUrl")); //false
        alert( Test.prototype.hasOwnProperty("showName1"));//true
        alert( Test.prototype.hasOwnProperty("siteUrl"));        //false
        alert( Test.prototype.isPrototypeOf(n1)); //true
        alert( Test.prototype.isPrototypeOf(n2)); //true
 
        e.g. 2
        Object.prototype.bar = 1;  //修改Object.prototype
        var foo = {goo : undefined };
        foo.bar;  // 1
        'bar' in foo;  //true
        foo.hasOwnProperty('bar');  //false
        foo.hasOwnProperty('goo'); //true
       
       
     ◆ isPrototypeOf(object): 用于检查传入的对象是否是另一个对象的原型。
     ◆ propertyIsEnumerable( propertyName ): 用于检查给定的属性是否能够使用for-in语句来枚举。与hasOwnProperty()方法一样,作为参数的属性名必须以字符串形式指定。
     ◆ toLocaleString(): 返回对象的字符串表示,该字符串与执行环境的地区对应。
     ◆ toString(): 返回对象的字符串表示。
     ◆ valueOf():  返回对象的字符串、数值、布尔值 表示。通常与toString()方法的返回值相同。
 
 *  函数(Functions)
     函数是JS中的一等对象,这意味着可把函数像其它值一样传递。一个常见的用法是把匿名函数作为回调函数传递对异步函数中。   
     foo(); //正常运行,因为foo在代码运行前已经被创建
     funcion foo(){}
    
     foo;  //'undefined'
     foo(); //出错:TypeError
     var foo = function(){};     //赋值语句只在运行时执行,如果把这句放在 foo();之前就OK
 
     var foo = function bar(){
          bar(); //正常运行
     };
     bar();  //出错: ReferenceError
      说明:bar函数声明外是不可见的,这是因为我们已经把函数赋值给了foo; 然而在bar内部依然可见。这是由于JS的命名处理所致,函数名在函数内部是可见的
    
* this 的工作原理
   在五种不同的情况下,this指向的各不相同:
     ◆ 全局范围内 --- this;    //指向 全局对象。
     ◆ 函数调用    --- foo();  //指向 全局对象。 
     ◆ 方法调用    --- test.foo();//this指向test对象。
     ◆ 调用构造函数---new foo();//如函数倾向于和new关键词一块使用,则我们称此函数是 构造函数。在函数内部this指向新创建的对象。
     ◆ 显式的设置this--- function foo(a,b,c){}; 
                                 var bar = {};
                                 foo.apply(bar ,[1,2,3]); //数组将会被扩展,如下所示
                                 foo.call( bar, 1, 2, 3);   //传递到foo的参数是: a = 1,  b = 2, c = 3
     当使用Function.prototype上的call 或 apply 方法时,函数内的this将会被  显式设置 为函数调用的第一个参数。
     因此函数调用的规则在上例中已经不适用了,在foo函数内 this 被设置成了bar。
      注意:在对象的字面声明语法中,this不能用来指向对象本身。因此var obj = {me: this}中的me不会指向obj,因为this只可能出现在上述的五种情况中。(这个例子中,如果是在浏览器中运行,obj.me等于window对象)
 
     注:第二个规则被认为是JS语言另一个错误设计的地方,因为它从来没有实际的用途。如下例:
          Foo.method = function(){
                 function test(){
                       // this 将会被设置为 全局对象  (浏览器环境中也就是window对象)
                 }
                 test();
          }
          一个常见的误解是test中的this将会指向Foo对象,实际上不是这样子的。
          为了在 test 中获取对Foo对象的引用,我们需要在method函数内部创建一个局部变量指向 Foo对象。
          Foo.method = function(){
                var that = this;
                function test(){
                     // 使用 that 来指向 Foo对象
                }
                test();
           }
           that只是我们随意起的名字,不过这个名字被广泛的用来指向外部的this对象。
 
         另一个看起来奇怪的地方是函数别名,也就是将一个方法赋值给一个变量。
         var test = someObject.methodTest;
         test();
         上例中,test就像一个普通的函数被调用;因此,函数内的this将不再被指向到someObject对象。
         虽然this的晚绑定特性似乎并不友好,但是这确实 基于原形继承 赖以生存的土壤。
             function Foo(){}
             Foo.prototype.method = function(){};
            
             function Bar(){}
             Bar.prototype = Foo.prototype;
 
             new Bar().method();
         当method 被调用时,this 将会指向 Bar 的实例对象。
 
   * 一元操作符
     1、递增 和 递减 操作符
        这种操作符不仅适用于整数,还可用于字符串、布尔值、浮点数值、对象。见如下规则:
         ◆ 在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减的操作。
             字符器变量 变成 数值变量。
         ◆ 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为NaN. 字符串变量变成数值变量.
         ◆ 在应用于布尔值false时,先将其转换为0再执行加减的操作。布尔值变量变成数值变量。
         ◆ 在应用于布尔值true时,先将其转换为1再执行加减的操作。布尔值变量变成数值变量。
         ◆ 在应用于浮点数值时,执行加减的操作。
         ◆ 在应用于对象时,先调用对象的valueOf()方法以取得一个可供操作的值。然后对该值应用前述规则。如果结果是NaN,则在调用toString()方法后再应用前述规则。对象变量变成数值变量。
          e.g.  var s1 = "2";
                 var s2 = "z";
                 var b  = false;
                 var f   = 1.1;
                 var o   = {
                       valueOf : function(){ return -1; }
                 };
                 s1++;           // 3
                 s2++;           // NaN
                 b++;            // 1
                 f--;             // 0. 100000000009 (由于浮点舍入错误所致)
                 o--;             // -2
 
      2、一元加 和 减 操作符
          var num = 25;
          num = +25;   //仍是25
          对非数值应用时,该操作符会像Number()转型函数一样对这个值执行转换。即布尔值false和true->0和1, 字符串值会被按照一组特殊的规则进行解析,而对象是先调用它们的valueOf() 和(或)toString()方法,再转换得到的值。如下例:
          var s1 = "01";
          var s2 = "1.1";
          var s3 = "z";
          var b = false;
          var f = 1.1;
          var o = { valueOf : function(){ return -1; } };
          s1 = +s1;  //1
          s2 = +s2;  // 1.1
          s3 = +s3;  // NaN
          b  = +b;    // 0
          f   = +f;    // 1.1
          o   = +o;   // -1
 
          //当用于 一元减操作符时
          s1 = -s1; //-1
          s2 = -s2; //-1.1
          s3 = -s3; //NaN
          b = -b;    //0
          f  = -f;    // -1.1
          o  = -o;   // 1
      3、乘法操作符
          规则:
            ◆ 如果乘积超过ECMAScript数值的表示范围,则返回Infinity 或 -Infinity;
            ◆ 如果有一个操作数是NaN,则结果是NaN;
            ◆ 如果是 Infinity 与 0 相乘,则结果是NaN;
            ◆ 如果是 Infinity 与 非0数值相乘, 则结果是 Infinity或 -Infinity,取决于有符号操作数的符号;
            ◆ 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
            ◆ 如果有一个操作数不是数值,则在后台调用Number()转换,然后再应用上面的规则。
       4、除法操作符
            规则:
            ◆ 如果商超过了ECMAScript数值的表示范围,则返回 Infinity 或 -Infinity;
            ◆ 如果有一个操作数是NaN, 则结果是NaN;
            ◆ 如果是Infinity / Infinity, 则结果是NaN;
            ◆ 如果 是 0/0,则结果是 NaN;
            ◆ 如果 分子不为0,分母为0,则结果是Infinity;
            ◆ 如果是 非零的有限数被零除,则结果是 Infinity 或 -Infinity,取决于有符号操作数的符号;
            ◆ 如果是Infinity被任何非零数值除,则结果是Infinity或-Infinity,取决于有符号操作数的符号;
            ◆ 如果有一个操作数不是数值,则在后台调用Number()转换,然后再应用上面的规则。
       5、求模(%)
           ◆ 如果被除数是无穷大,除数是有限大的数值,则结果是NaN;
           ◆ 如果被除数是有限大,除数是0,则结果是NaN;
           ◆ 如果是 Infinity / Infinity,则结果是NaN;
           ◆ 如果被除数是有限大的数值,除数是无穷大的数值,则结果是被除数;
           ◆ 如果被除数是0,则结果是0;
           ◆ 如果有一个操作数不是数值,则在后台调用Number()转换后再应用上面的规则。
       6、加性质操作符
          1> 加法操作符规则:
              ◆ 如果有一个是NaN,则结果是NaN;
              ◆ 如果是Infinity + Infinity = Infinity;
              ◆ 如果是 -Infinity + -Infinity = -Infinity;
              ◆ 如果是 Infinity + -Infinity = NaN;
              ◆ 如果是 +0 加上 +0 = +0;
              ◆ 如果是 -0 加上 -0 = -0;
              ◆ 如果是 +0 加上 -0 = +0;
              ◆ 如果两个操作数都是字符串,则将第二个操作数 与 第一个操作数 拼接起来;
              ◆ 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来.
              ◆ 如果有一个操作数是 对象、数值、布尔值,则调用它们的toString()方法取得相应的字符串值,然后再应用上两条关于字符串的规则。对于 undefined 和 null,则分别调用String()函数并取得字符串"undefined" 和 "null".
               e.g.   var r = 5+"5";  //"55"
                       var k = "Result: " + 5 + 10; //Result: 510    "Result: "+5 --> "Result: 5" + 10
         2> 减法操作符(-)
              ◆ 如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
              ◆ 如果有一个操作数是NaN,则结果是NaN;
              ◆ 如果是Infinity - Infinity = NaN;
              ◆ 如果是 -Infinity - -Infinity = NaN;
              ◆ 如果是 Infinity - -Infinity = Infinity;
              ◆ 如果是 -Infinity - Infinity = -Infinity;
              ◆ 如果是 +0 - +0 = +0;
              ◆ 如果是 +0 - -0  = -0;
              ◆ 如果是 -0  - -0  = +0;
              ◆ 如果有一个操作数是 字符串、布尔值、null、undefined,则先在后台调用Number()函数将其转换为数值,然后再根据前面的规则执行减法计算。如果转换的结果是NaN,则减法的结果就是NaN;
              ◆ 如果有一个操作数是 对象,则调用 对象的valueOf()方法以取得表示该对象的数值。如果得到的值是NaN,则减法的结果就是NaN。如果对象没有valueOf()方法,则调用其toString()方法并将得到的字符串转换为数值。
               e.g. var r = 5 - true;  // 4, true->1
                     var r = NaN - 1;  //  NaN
                     var r = 5 - "";     //  5, "" -> 0
                     var r = 5 - "2";   //  3, "2"->2
                     var r = 5 - null;  //  5, null -> 0
        7、关系操作符(>、<、>=、<=)
            规则:
               ◆ 如果两个操作数都是数值,则执行数值比较; 
               ◆ 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值; 
               ◆ 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较; 
               ◆ 如果一个操作数是对象,则调用这个对象的valueOf()方法,并用得到解决的结果根据前面的规则执行比较; 
               ◆ 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较;
          e.g.  var r = "Brick" < "alphabet";  //true   
                 var r = "Brick".toLowerCase() < "alphabet".toLowerCase(); //false
                 var r = "23" < "3";  //true   "2"的编码是50, "3"的编码是51
                 var r = "23" < 3;    //false  "23"->23 < 3 -> false  "23"会被转换成数值23
                 var r = "a" < 3;      //false  因为"a"被转换成NaN
                 var r = NaN < 3;    //false
                 var r = NaN >=3;   //false
                 
           1> 相等 和 不相等
               ◆ 如果有一个是布尔值,则在比较前先转换为数值---false->0,true->1;
               ◆ 如果有一个是字符串,另一个是数值,在比较前先将字符串->数值;
               ◆ 如果有一个是对象,别一个不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较;
               ◆ null 和 undefined 是相等的; 
               ◆ 要比较相等性之前,不能将null 和 undefined 转换成其他任何值; 
               ◆ 如果有一个操作数是NaN, 则相等操作符返回false,而不相等操作符返回true。注:即使两个操作数都是NaN,相等操作符也返回false;因为按照规则,NaN不等于NaN。
               ◆ 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true;否则,返回false;
               e.g.  null == undefined     //true
                      "NaN" == NaN          //false
                       5 == NaN               //false
                      NaN == NaN            //false
                      NaN != NaN             //true
                      false == 0               //true
                      true == 1                //true
                      true == 2                //false
                      undefined == 0        //false
                      null == 0                 //false
                      "5" == 5                 //true
   
                      null == undefined    //true
                      null === undefined  //false 因为它们是不同类型的值

           2>  逗号操作符
                用于声明多个变量,但除此之外,逗号操作符还可用于赋值。在用于赋值时,逗号操作符总会返回表达式中的最后一项,如下面的例子所示:
                var num = (5, 1, 4, 8, 0);  //num的值为0
                由于0是表达式中的最后一项,因此num的值就是0。虽然逗号的这种方式并不常见,但此例可帮我们理解逗号的这种行为。 
        
       8、break 和 continue语句都可以与label语句联合使用,从而返回代码中特定的位置。这种联合使用的情况多发生在循环嵌套的情况下,如下面的例子所示:
         var num = 0;
          outermost:
         for(var i=0; i<10; i++){
             for(var j=0; j<10; j++){
                  if( i==5 && j==5 ){
                        break outermost;   //continue outermost;
                  }
             }
          }
          alert(num); //55

     9、switch语句在比较值时使用的是全等操作符,因此不会发生类型转换(例如,字符串"10"不等于数值10).

     10、函数function
          function sum(num1, num2){
                return num1 + num2;
                alert("Hello world");    //永远不会执行
          }
          
          function sayHi(name, message){
               return;   //return语句也可不带有任何返回值,这时函数在停止执行后将返回undefined值。 
          }

          推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候有不返回值,会给调试代码带来不便。

          严格模式对函数有一些限制:
          ◆ 不能把函数命名为 eval 或 arguments;
          ◆ 不能把参数命名为 eval 或 arguments;
          ◆ 不能出现两个命名参数同名的情况。
          如果发生以上情况,就会导致语法错误,代码无法执行。
          1> 理解参数
            ECMAScript中的函数参数在内部是用一个类似数组的arguments对象表示的。
            e.g.  function Args(){ alert( arguments.length ); }
                    Args("string",45);   //2
                    Args();                  //0
                    Args(12);              //1
           
                    function add(num1, num2){
                          arguments[1] = 10;
                          alert( arguments[0] + ", " + num2 );//num1被改变了,用num1=10也同样改变
                    }
                    add(2,3);   //2, 10
                    
                    function add(num1, num2){
                          arguments[1] = 10;
                          alert( arguments[0] + ", " + num2 );//第二个参数没给,函数里怎么改都不行
                    }
                    add(2);   //2, undefined
                注:ECMAScript中的所有参数传递的都是值,不可能通过引用传递参数。
           2、没有重载
                function add(num){ return num+100; }
                function add(num){ return num+200; }
                add(100); //300  如果定义两个同名函数,后一个覆盖前一个
       小结:
            ◆ ECMAScript中的基本数据类型包括Undefined、Null、Boolean、Number、String;
            ◆ Number类型可用于表示所有数值;
            ◆ Object类型是JS中所有对象的基础类型;
            ◆ 严格模式为这门语言中容易出错的地方施加了限制;
            ◆ 未指定返回值的函数返回的是一个特殊的undefined值;
            ◆ JS中也没有 函数签名的概念,因为其函数参数是以一个包含 零个/多个值的数组的形式传递的;
            ◆ 函数可传递任意数量的参数,并可通过arguments对象来访问这些参数;
            ◆ 由于不存在函数签名的特性,ECMAScript函数不能重载。
       
       
变量、作用域、内存问题
按照ECMA-262的定义,JS的变量与其他语言的变量有很大区别。JS变量松散类型的本质,决定了它只是在特定时间用于保存特定值的一个名字而已。由于不存在定义某个变量必须要保存何种数据类型值的规则,变量的值及其数据通信类型可以在脚本生命周期内改变。尽管从某种角度看,这可能是一个既有趣又强大,同时又容易出问题的特性,但JS变量实际的复杂程度还远不止如此。
     1、基本类型 和 引用类型 的值
         ECMAScript变量可能包含两种不同数据类型的值:基本类型 和 引用类型值。
         在将一个值赋给变量时,解析器必须确定这个值是基本类型值 还是 引用类型值。
         
         ◆ 基本类型值 指的是简单的数据段(Undefined、Null、Boolean、Number、String)
         ◆ 引用类型值 指的是那些可能由多个值构成的对象。引用类型的值是保存在内存中的对象。与其他语言不同,JS不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。
注: 在很多语言中字符串以对象的形式来表示,因此被认为是引用类型. ECMAScript放弃了这一传统.

       2、动态属性
          对于 引用类型的值,可为其添加属性和方法,也可改变和删除其属性和方法,如下: 
          var person = new Object();
          person.name = "Nicholas";   //为对象person添加属性name
          alert( person.name );
         
          但不能给基本类型的值添加属性,尽管这么做不会导致任何错误,比如: 
          var name = "Nicholas";
          name.age = 27;
          alert(name.age); 
       3、复制变量值
          从一个变量 向 另一个变量 复制基本类型 和 引用类型值时,也存在不同。  
          如从一个变量 向 另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。如下例: 
          var num1 = 5; 
          var num2 = num1;  //num2保存了值5;num2中的5与num1中的5是完全独立的,是num1中5的一个副本,互不影响。
          
          当一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到 为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量,如下所示:
          var obj1 = new Object();
          var obj2 = obj1;  //obj1 和 obj2都指向同一个对象。
          obj1.name = "Nicholas";
          alert( obj2.name ); //"Nicholas"
          
       4、传递参数
       ECMAScript中所有函数的参数都是按值传递的. 也就是说, 把函数外部的值复制给函数内部的参数,就和把值从一个变量 复制到 另一个变量一样.
          e.g. function addTen(num){ num+=10; return num; }
                var count = 20;
                var result = addTen( count );
                alert( count ); //20 没有变化
                alert( result ); //30
                //在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量
 
                function setName( obj ){ obj.name = "Nicholas"; }
                var person = new Object();
                setName( person );
                alert( person.name );  //"Nicholas"
                //在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部.
 
      以上代码中创建一个对象,并将其保存在了变量person中。然后,这个对象被传递到setName()函数中之后就被复制给了obj。在这个函数内部,obj和person引用的是同一个对象。换句话说,即使这个对象是按值传递的,obj敢会按引用来访问同一个对象。于是,当在函数内部为obj添加name属性后,函数外部的person也将有所反映;因为person指向的对象在堆内存中只有一个,而且是全局对象。
有很多人错误地认为:在局部作用域修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。为了证明对象是按值传递的,看下例:
          function setName( obj ){
              obj.name = "Nicholas";
              obj = new Object();
              obj.name = "Greg";
          }
          var person = new Object();
          setName( person );
          alert( person.name );   //"Nicholas"
          如果person是按引用传递的,那么person就会自动被修改为指向其name属性值为"Greg"的新对象。但是,当接下来再访问person.name时,显示的值仍然是"Nicholas"。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持不变。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值