JavaScript深入【词法结构,类型,值和变量】原来也不简单

 

 

博主留言 (茗洋芳竹  


我自己本身是个ASP.NET开发者,前后台数据库都搞,所以各个方面都不是那么精通,连个JavaScript,最后也想偷懒,用了Jquery,忘了原生的高深莫测的Javascript,特写博客,系统学习Javascript,本文不太适合零基础学习的人,至少有其他编程语言小基础的的javascript学习者。

当你系统的学习Javascript的时候,你会觉得还是有必要的,这就是超过别的程序员的地方

本文开头看似很简单,但当我写完这篇博客的时候我发现,我有好多不知道的。

  比如说

       字符串的原理

       字符集,Unicode,字符的长度到底怎么算出来的,比如 var b="caf\u00e9"var c="cafe\u0301"; b的长度是多少,c的长度是多少,答案是一个是4,一个是5

       JavaScript的浮点数到点是怎么计算的,比如 1.4738223E-32是什么意思,0.3-0.2等于0.1吗?.4-.3等于0.1吗

       当遇到财务计算,要求精度,你会怎么做

      字符串一些处理方法,比如slice方法,字符串的正则 方法处理

      两个字符串的比较原理

      null与undefined

      Infinity和-Infinity,NaN

      全局对象的真正理解,而不再浅浅的理解

      原始值与对象的相互转换

      valueOf与toString

      还有个很神奇,跟其他比如C#,Java不一样的函数作用域,而不是块级作用域,作用域嵌套

      var这个关键字,声明时真的可写可不写吗

      等等

      

我相信如果你不是Web前端开发人员,你肯定受益匪浅。

 

JavaScript简单调试(茗洋芳竹


你可以打开火狐,谷歌或者IE,现在好多浏览器自带了 开发者工具,作为简单的入门调试环境

例如我打开了谷歌浏览器,按下F12,然后点击Console,截图如下

image

此刻你可以直接在下面写JavaScript代码,然后进行学习和测试

小提示:

例如我们写下 alert("Hello Javascipt!") 然后按下回车,会弹出对话框

image

但是如果超过两行Javascript代码测试时候

我们可以写完一行代码时候,按下Shift+Enter执行换行

然后继续编写代码

 

后期,我们主要用SublimeText去写代码,当然你也可以用其他文本编辑器或者 web开发工具,例如 adobe Dreamweaver CS系列,最新的好像是cs 6

 

JavaScript小Tip(茗洋芳竹


1. Javascript 程序是用Unicode字符集编写的

    Unicode是ASCII和Latin-1的超集,并支持地球上几乎所有在用的语言

2. Javascript 区分大小写,但是HTML不区分大小写(严格讲XHTML区分大小写,但是浏览器纠错能力强大,还是可以宽容地正确解析渲染)

   星星在HTML中,标签和属性名可以使用大写也可以小写,而在JavaScript中必须小写。

        例如:在HTML中设置事件处理程序时,onclick可以写成onClick,但在Javascript中,必须小写onclick

3. 在编写Javascript代码中可以随意使用空格和换行,因此编写的代码可以弄整齐,一致的缩进,提高代码可读性

4. 为了支持使用老旧技术的程序员,javascript定义了一种特殊序列,使用6个ASCII字符来代表任意16位Unicode内码

    形式:\u为前缀,其后跟随4个十六进制数。例如 \u0020表示空格

    这种Unicode转义写法可以用在Javascript字符串直接量、正则表达式直接量和标志符中(关键字除外)

    image=>true

5. Unicode允许使用多种方法对同一个字符进行编码

    比如,字符“é”可以使用Unicode字符\u00E9表示,也可以使用普通的ASCII字符e加上一个语调符\u0301。

<script>
 var a="café";
 var b="caf\u00e9";
 var c="cafe\u0301";
 alert(b+"  "+c);
</script>

    显示效果

image

    我们顺便借这个机会测试一下其他方面的东西,例如字符长度

<script>
 var a="café";
 var b="caf\u00e9";
 var c="cafe\u0301";
 alert(b+"  "+c);   
 alert(a===b);
 alert(b==c);
 alert("caf\u00e9的长度等于"+b.length+"\ncafe\u0301"+"的长度等于"+c.length);
</script>
 
结果: 
   a===b // =>true      
   b==c   //=>false                                         

         b.length是4,而c.length是5                                 

      所以这两种编码的显示结果一模一样,但他们的二进制编码表示是不一样的,在计算机里面也不相等

 

6. 注释

    // 单行注释

   /* 只是另一段注释 */

   /*

   *这又是一段注释

   *这个注释可以写多行

   */

 

7. 直接量(literal)

   程序中直接使用的数据值

   12 //数字

   1.2 //小数

   "Hello world”    //字符串文本

   ‘Hi’     //另一个字符串

    true    //布尔值

    /javascript/gi      //正则表达式直接量(用做模式匹配)

    null         //空

   更多复杂的表达方式,可以写成数组或对象直接量

  {x:1,y:2} //对象

  [1,2,3,4,5]  //数组

 

8. 标识符

   标识符就是一个名字,标识符用来 对变量和函数进行命名,或者用做JS代码中某些循环语句中的跳转位置的标记。JS标识符必须以字母、下划线(_)或美元符($)开始,后续的字符可以是字母、数字(不允许作为首字符出现)、下划线或者美元符。

   例如

         i

         my_mingyangfangzhu_blog

         v13

         _dummy

        $str

   出于可移植性和易于书写的考虑,通常我们只使用ASCII字母和数字来书写标识符。然而需要质疑的是,Javascript允许标识符中出现Unicode字符全集中的字母和数字。我们也可以使用非英语语言数字符号来书写标识符

  例如: var sí=true;

           var π =3.14;

 

9. 保留字

    Javascript把一些 标识符拿出来 用作自己的关键字。所以我们就不能再在程序中把这些关键字用作标识符了。

    如果学过其他语言的,一听就懂了。标识符就是一个变量名,有些特殊的变量名不能再定义了,那就是保留字

    JS中,例如

    break delete function return typeof case do if switch var catch else in this void continue false instanceof throw

    while debugger finally new true with default for null try等

    JS还定义了很多全局变量和函数

    arguments                      encodeURI                             Infinity             Number                    RegExp

    Array                             encodeURIComponent              IsFinite            Object                       String          

    Boolean                         Error                                     IsNaN              parseFloat                  SyntaxError

    Date                              eval                                      JSON                parseInt                     TypeError

    decodeURI                      EvalError                               Math                 RangeError                  undefined

    decodeURIComponent      Function                                NaN                 ReferenceError              URIError

    等

    JavaScript的具体实现可能定义独有的全局变量和函数,每一个特定的JavaScript运行环境(客户端、服务器端等)都有自己的一个全局属性列表,这一点需要牢记。每个浏览器可能自带某些js内置函数

 

10.可选的分号

   例如代码

    例一                                                

      a=3;

      b=4;

   考虑如上代码,因为两条语句用两行书写,第一个分号是可以省略掉的,但是如果这样写,就不可省略掉了

     a=3;b=4;

   例二                                 

  var a

  a

  =

  3

  console.log(a)

 

Javascript将其解析为

var a;a=3;console.log(a);

Javascript给第一行换行处添加了分号,因为如果没有分号,JavaScript就无法解析代码var a a.

第二个a可以单独当做一条语句”a;”,但JavaScript并没有给第二行结尾填补分号,因为他可以和

第三行内容一起解析成"a=3”;

 

   例三                                    

var y=x+f

(a+b).toString()

看似两行,你也想到了,JavaScript会把这段代码看做: var y=x+f(a+b).toString(); 

f被看做是一个方法,所以要达到的自己的本意,必须手动填写行尾的显示分号

不同的人,不同的JavaScript编码风格,有的程序员喜欢保守地在语句前加上一个分号,这样哪怕之前的语句被修改了、分号被误删除了,当前语句还是会正确的解析

     var x=0

     ;[1,2+1,3+2].forEach(…) //前面的分号保证了正确地语句解析

 

  例四                               

return

true;

JavaScript会解析成:

return;true;

而你的本意是 return true;

也就是说,在return、break和continue和随后的表达式之间不能有换行。

 

还有个例外,例如

x

++

y

这段代码将解析为 “x;++y”而不是“x++;y”

 

 

 

JavaScript 类型、值和变量 (茗洋芳竹 


这几个字我觉得比较抽象,如果做过其他语言学习的人那就最简单的了,懒得说大定义,会感悟出来的

一句话概括:

   计算机程序的运行需要对 值(value) 进行操作。

   在编程语言中,能够表示,并操作的值的类型,称作数据类型(type)

    编程语言最基本的特性就是能够支持多种数据类型。当程序需要将值保存起来以备将来使用时,便将其赋值给一个变量(variable)

 

JavaScipt的数据类型分为两类:原始类型和对象类型

JavaScipt中有两个特殊的原始值:null(空)和undefined(未定义),它们不是数字,字符串和布尔值。

JavaScipt中除了数字、字符串、布尔值、null和undefined之外的就是对象了

JavaScipt解释器有自己的内存管理机制,可以自动对内存进行垃圾回收

JavaScipt是一种面向对象的语言

从技术上将,只有JavaScript对象才能拥有方法。然后数字、字符串和布尔值也可以拥有自己的方法。只有null和undefined是无法拥有方法的值。

JavaScipt变量是无类型的,变量可以被赋予任何类型的值,同样一个变量也可以重新赋予不同类型的值。使用 var 关键字来声明变量。JavaScipt采用词法作用域(lexical scoping)。

不在任何函数内声明的变量称作全局变量(global variable),它在JavaScript程序中的任何地方都是可见的。在函数内声明的变量具有函数作用域(function scope),并且只在函数内可见。

 

以上的很多东西,在编写代码中会慢慢领悟的

 

【数字】

 1. JavaScipt 不区分整数值和浮点数值JavaScipt 中的所有数字均用浮点数值表示。

    最大值:±1.7976931348623157 × 10的308次方

    最小值:±5× 10的负324次方

2.JavaScipt 除了常见十进制,JavaScipt 同样也能识别十六进制值(以“0x”或“0X”开头,然后跟着0~9或者A~F或者a~f字母组成,A(a)~F(f)分别代表数字10~15)

   例如:

      0xff         //从右往左数到X(x)停住,16的0次方,16的1次方,f代表15,所以转换成十进制后是

                       15乘以16的1次方+15乘以16的0次方,最后等于255

image

尽管ECMAScript标准不支持八进制直接量,但JavaScript的某些实现可以允许采用八进制形式的整数,八进制以数字0开始,其后跟随一个由0~7之间的数字组成的序列

例如

  0377     //从右往左数到开头的0停住,8的0次方,8的1次方,8的2次方,所以转换成十进制后是

                       3乘以8的2次方+7乘以8的1次方+7乘以8的0次方,最后等于

                        3*64+7*8+7*1=255

image

 

3.浮点型

  就是 一个实数由 整数部分+小数点+小数部分   组成

  例如:

     3.14

     2345.678

     .33333333

     6.02e23         //特别说明:等同于 6.02 ×clip_image002_thumb[1]

    1.4342E-23     //特别说明:等同于 1.4342 ×clip_image002

   除了加(+)减(-)乘(*)除(/)求余(%)几个运算外,还有很多

    JavaScript还支持更加复杂的算数运算

<script>
 
 //Math类运算
 var a=Math.pow(2,53);     //=>9007199254740992   也就是2的53次幂
 var b=Math.round(.6);     //=>1.0       四舍五入
 var c=Math.ceil(.6);      //=>1.0   向上求整,大于它的最小整数
 var d=Math.floor(.6);     //=>0.0    向下求整,小于它的最大整数
 var e=Math.abs(-5);       //=>5;      求绝对值
 
 
 var f=Math.max(3,5,1);     //返回最大值
 var g=Math.min(3,5,1);     //返回最小值
 
 
 var h=Math.random();       //生成一个大于等于0小于1.0的伪随机数
 var pi=Math.PI;            //π,圆周率
 var i=Math.E;              //自然对数的地鼠
 var j=Math.sqrt(3);        // 3的平方根
 var k=Math.pow(3,1/3);     // 3的立方根,这里第二个参数 指的是 幂右上角的指数,读作3的三分之一次方
 var l=Math.sin(0);         //三角函数,还有Math.cos,Math.atan等等
 var m=Math.log(10);        //10的自然对数
 var n=Math.log(100)/Math.LN10 ;   //以10为底100的对数
 var o=Math.log(512)/Math.LN2 ;    // 以2为底512的对数
 var p=Math.exp(3);                //e的三次幂
 
 
</script>

 

JavaScript 中的算数运算在 溢出(overflow),下溢(underflow)或被零整除时候不会报错。当数字运算结果超过了JavaScript所能表示的数字上限(溢出),结果为无穷大(infinity)值,在JavaScript中以Infinity表示,同样地,当负数的值超过了JavaScript所能表示的负数范围,结果则为负无穷大,在JavaScript中以-Infinity表示

下溢 是当运算结果无限接近于零并比JavaScript能表示的最小值还小的时候发生的一种情形。这种情况,JavaScript会返回0.当一个负数发生下溢时,JavaScript返回一个特殊的值“负零”。这个零(负零)几乎和正常的零是一样的

被零整除在JavaScript并不报错;只是简单的返回无穷大(Infinity)或者负无穷大(-Infinity)。

零除以零无意义,返回NaN,任何无意义的,例如给任意负数做开方,都将返回NaN

JavaScript 预定了全局变量 InfinityNaN,用来表示正无穷大和非数字值。ECMAScript5将它们定义为只读的。在ECMAScript3中

Number对象定义的属性值也是只读的,

比如:

  Infinity                             //将一个可读/写的变量初始化为infinity

  Number.POSITIVE_INFINITY    //同样的值,只读

  如下:则会显示个  true

 var aa= Number.POSITIVE_INFINITY;
 alert(aa==Infinity);

1/0       //这也是同样的值

  image

Number.MAX_VALUE+1      //还是Infinity

 

以下几个是负无穷大

Number.NEGATIVE_INFINITY,-Infinity,-1/0,Number.MAX_VALUE-1

 

以下几个是NaN

NaN,Number.NaN,0/0

 

以下几个是负零

-0,-Number.MIN_VALUE/2,-1/Infinity

 

Number.MIN_VALUE/2 发生下溢,计算结果为0

 

注意:JavaScript中的非数字有一点特殊,第一种判断是false,isNaN()方法,如果cc是NaN,则为true,否则为false

<script>
 
 var cc=NaN;
 if(cc==NaN){
     alert("是NaN");
  }else{
     alert("不是NaN"); 
       }
 
 if(isNaN(cc)){
      alert("是NaN");
     }else{
     alert("不是NaN"); 
       }
</script>

 

还有个 函数 isFinite()方法,除 NaN,Infinity,-Infinity其他都是true

var dd2=-Infinity;
var dd3=NaN;
var dd4="22";
var dd5=true;
//inFinite()
alert(isFinite(dd1));  // false
alert(isFinite(dd2));  // false
alert(isFinite(dd3));  // false
alert(isFinite(dd4));  // true
alert(isFinite(dd5));  // true
 
 
 
负零值也有些特殊,这两个值几乎一模一样,除了做除数之外;
var zero=0;
var negz=-0;
alert(zero===negz);           // true   正零值和负零值相等
alert(1/zero===1/negz);       // false  正无穷大和负无穷大不等
 
 
 
 
 

4.当在JavaScript 中使用实数的时候,常常只是真实值的一个近似表示

    JavaScript 采用了IEEE-754浮点数表示法(几乎所有现代编程语言所采用),这是一种二进制表示法,可以精确地表示分数,比如1/2,1/8,1/1024,分子是2的n次方数,遗憾的是,我们常用分数(特别在金融计算方面)都是十进制分数1/10,1/100等。

所以二进制浮点数表示法冰冷精确表示类似0.1这样简单的数字

 

var x=.3-.2;
var y=.2-.1;
alert(x==y);   //=>false
alert(x==.1);  //=>false
alert(y==.1);  //=>true
 

所以在任何使用二进制浮点数的编程语言都会有这个问题。例如,要使用整数“分”而不要使用小数“元”进行基于货币单位的运算。

 

5.日期和时间

   JavaScript 语言核心包括Date()构造函数,用来创建表示日期和时间的对象

var then=new Date(2013,2,20);  //2013年3月20日
var later=new Date(2013,2,20,17,10,30); //同一天,当地时间 5:10:30pm
var now=new Date();   //当前日期和时间
var elapsed=now-then;  //日期减法,计算时间间隔的毫秒数
var year=later.getFullYear(); //2013
var month=later.getMonth();   //0, 从0开始计数的月份
var day=later.getDate();     //20,从1开始计算天数
var week=later.getDay();     //3,0代表星期日,3代表星期三,6代表星期6
var hours=later.getHours();   //17,当地时间17:10pm中的小时数字
var lc=later.getUTCHours()  //使用UTC表示小时的时间,基于时区
 

 

6.字符串直接量 例如 "" //空字符串

       "茗洋芳竹123"
      'myname="myfz"'
     "it's  a  book"
      "lala\n123\n

π

"     //      \n代表转行
         等等
 

在ECMAScript3中,字符串直接量必须写在一行中 在ECMAScript5中,字符串直接量可以拆分数行,每行必须以反斜线(\)结束,如果希望在字符串直接量中另起一行,可以使用转义字符\n

var newLine="long\
  long\
             ago";
             alert(newLine);

注意 当使用单引号来 定界字符串时,需要格外小心英文中的缩写和所有格写法,比如 it’s 和 can’t。

         因为撇号和单引号是同一个字符,所以必须使用反斜线(\)来转义所有的撇号

 

7. 转义字符

  反斜线符号后面加一个字符,就不在表示他们的字面含义了

   例如\n 表示一个换行符

         \'  表示单引号(或撇号)

   通过十六进制数表示Latin-1或Unicode的任意字码。例如\x09 表示版权符号,版权符号的Latin-1编码是十六进制数A9。

   同样,\u表示由4个十六进制数指定的任意Unicode字符,比如\u03c0表示 π

     类似的还有很多,例如 \"  表示 双引号(\u0022

        \\  表示 反斜线(\u005c)                                      

      \r  表示 回车符(\u000d)                                        

      \t  表示 水平制表符(\u0009)                                   

     \v   表示 垂直制表符(\u000B)                                  

     \b   表示 退格符(\u0008)                                       

     \xXX 表示 由两位十六进制数XX指定的Latin-1字符         

     \xXXXX  由4位十六进制数XXXX指定的Unicode字符       

 

 

 

8. 字符串使用

   ①连接字符串用+号     var c=”Chris”+”  Li”;

   ②字符串.length    获得字符串长度

  常用方法

<script>
   var s="hello world";
   var s1=s.charAt(0);                         // h :获得第一个字符
   var s2=s.charAt(s.length-1);                // d :获得最后一个字符
   var s3=s.substring(1,4);                    //ell: 第2-4个字符
   var s4=s.substr(2,5);                       //llo w: 从0开始,第一个字符是h,第二个l,第三个字符就是l,然后取5个长度的字符
   var s5=s.slice(1,4);                        //ell: 第2-4个字符
   var s6=s.slice(-3);                         //rld:最后3个字符
   var s7=s.slice(3);                          //lo world:从第3个字符开始,取到末尾
   var s8=s.indexOf("l");                      //2,从0开始,首次出现l的位置
   var s9=s.lastIndexOf("l");                  //9,从0开始,字符l最后出现的位置 
   var s10=s.indexOf("l",3);                   //3,在位置3及之后首次出现字符l的位置
   var s11=s.split(" ");                       //["hello","world"] 分割成字符串
   var s12=s.replace("h","H");                  //"Hello world": 全文字符替换
   var s13=s.toUpperCase();                     //"HELLO WORLD" :转换成大写字母
   
</script>

记住,在JavaScript中字符串是固定不变的,类似replace()和toUpperCase()的方法都返回新字符串,原字符串本身并没有发生改变

在ECMAScript5中,字符串可以当做只读数组。

 var s="hello world";
    alert(s[0]);        //h
    alert(s[s.length-1]); //d

这种类似于charAt 函数方法,加上数字索引 访问数组中的单个字符

 

9.模式匹配

  JavaScript 定义了RegExp()构造函数,用来创建表示文本匹配模式的对象,这就是正则表达式

  String和RegExp对象均定义了 利用正则表达式 进行模式匹配和查找与替换的函数

  RegExp和Date一样,只是一种具有实用API的特殊对象。这里只是正则表达式的一个概述,具体后面讲

  例如:

       /^HTML/      //匹配以HTML开始的字符串

      /[0-9][0-9]*/      //匹配一个非零数字,后面是任意个数字

     /\bjavascript\b/i   //匹配单词“javascript”,忽略大小写

 

字符串同样具有可以接受RegExp参数的方法

  var text="testing:1,2,3";
  var pattern=/\d+/g;      //匹配所有包含一个或多个数字的实例 ,\d代表数字,+号对前面的数字进行约束,表示至少一个
  alert(pattern.test(text));      //true
  var succLo=text.search(pattern);     //9 首次匹配成功的位置
  var arrSucc=text.match(pattern);     //所有符合匹配要求的,所有匹配组成的数组 ["1","2","3"]
  var replaceSucc=text.replace(pattern);   //testing,#,#,#
  var splitSucc=text.split(/\D+/);          //用非数字字符 作为 分组条件 ["","1","2","3"]
  alert(splitSucc.length);       //4

 

 

10.布尔值

    布尔值(bool) 表示真假,保留字为true和false

     一个表达式最终会成不成立,就是 true或者false

    一个逻辑最终成不成立,就是true或者false

   

  注意 JavaScript的值都可以转换成布尔值,下面这些值会被转换成false

            undefined,null,0,-0,NaN

           ””

     &&运算执行了逻辑与(And)操作

     || 运算 执行了布尔或(OR)操作

      !运算 执行了非(NOT)操作

     例子:a1是true,a2是true,所有a1&&a2是true;a3是false进行了非操作,取反,则是true

             然后 true||true,或操作是只要有一个是真,整个条件就为真,所以最终返回true

 var x=0,y=0,z=2;
  var a1=x==0;
  var a2=y==0;
  var a3=z==0;
 
  var a4=(a1&&a2)||(!a3);
  alert(a4);

 

 

 

11. null和undefined

    对null执行typeof运算,结果返回字符串object,也就是说,可以将null值认为是一个特殊对象值

    对undefined执行typeof算,结果返回字符串undefined,用未定义的值表示更深层次的“空值”。他是变量的一种取值,表明变量没有初始化。如果要查询对象属性或数组元素的值返回undefined则说明这个属性或元素不存在

    尽管null和undefined是不同的,但他们都表示值的空缺,两者往往可以互换。判断相等运算符“==”认为两者是相等个(要使用严格相等运算符“===”来区分它们),它们不包括任何属性和方法,放入[]数组会产生类型错误

    如果你想将它们赋值给变量或者属性,或将他们作为参数传入函数,最佳选择用null

 

 

 

12.全局对象的属性时全局定义的符号,JavaScript程序可以直接使用

   全局属性:比如undefined,Infinity和 NaN

   全局函数,比如isNaN(),parseInt()和Eval()

   构造函数  比如Date(),RegExp(),String(),Object()和Array()

   全局对象  比如Math和JSON

 

 

13.包装对象

    JavaScript 通过“.”符号来引用属性值。当属性值是一个函数的时候,称其为方法。通过o.m()来调用对象o中的方法

   下面一段代码是错误的,返回undefined,第二行代码创建一个临时字符串对象,并给其len属性赋值给4,随即销毁这个对象。第三行通过原始的字符串值创建一个新字符串对象,当你尝试读取其len属性,这个属性自然不存在

 var bao="test";
  bao.len=4;
  alert(bao.len);

 

  需要注意的是,可通过String(),Number()或 Boolean()构造函数来显示创建包装对象

  var s="test",n=1,b=true;
  var S=new String(s);     //一个字符串对象
  var N=new Number(n);     //创建一个数值对象
  var B=new Boolean(b);   //创建一个布尔对象

 

 

14.天使不可变的原始值和可变的对象引用

     关于这个,我感觉很重要,不仅仅对于JavaScript语言来讲的

      1.JavaScript的原始值(undefined、null、布尔值、数字和字符串)与对象(包括数组和函数)有着根本区别。原始值不可更改

      2.字符串看起来是字符组成的数组,我们希望通过索引修改字符串中的字符,Js是进制这样做的。字符串中所有的方法看上去返回了一个修改后的字符串,实际上是一个新的字符串。

  var s="hello world";
  var t=s.toUpperCase();
  alert(s+"   "+t);

      把 s 的一个副本转换成了大写,然后返回给了t,原始的s值没有改变。

      3.原始值的比较是值的比较,只有在他们的值相等时他们才相等。数字、布尔值、null、undefined都是这样比较的,因为没有其他办法

      4.两个单独的字符串比较,当且仅当他们的长度相等且每个索引的字符都相等时,JavaScript才认为他们相等

  var array1=[1,4,5];
  var array2=[1,4,5];
  var array3=[3,4,5];
  
  
  alert(equalArray(array1,array2));
  alert(equalArray(array1,array3));
    
  function equalArray(a,b){
      //先比较两个数组的长度
      if(a.length!=b.length)return false;
      //如果数组中的任意元素不相等,则数组不相等
      for(var i=0;i<a.length;i++){
        if(a[i]!=b[i])return false;  
          }
          
          return true;
      }

      

       5.对象与原始值不同,他们的值是可以修改的

var o1={x:1};    //定义一个对象
    o1.x=2;       //通过修改对象属性值来更改对象
    o1.y=3;       //再次更改这个对象,给它增加一个新属性
    
alert(o1["x"]+"  "+o1.x+"   "+o1.y);     //2      2      3

 

      6.数组也是一样

      var o2=[1,2,3] ;     //数组也可以修改
      alert(o2.length);    //3
      o2[0]=0;              //更改
      o2[3]=4;              //新增
      
      alert(o2[0]+"  "+  o2[3]+"   "+o2.length);      //0     4     4

 

     7.对象的比较并非的比较;即使两个对象包含同样的属性及相同的值,他们也是不相等的。各个索引元素完全相等的两个数组也不想等。我们通常将对象称为引用类型(reference type)

        对象值都是引用,对象的比较均是引用的比较,当且仅当他们引用  同一个基对象(父对象)时,它们才相等

var o={x:1},p={x:1};  
     alert(o==p);     //都是false
     alert(o===p);    //都是false
     //两个单独的对象永不相等,它们存在内存中的地址不一样,地址唯一不重复的,所以永不相等
     
     var a=[],b=[];
     alert(a==b);     //都是false
     alert(a===b);    //都是false,跟上面一样的,两个单独的数组永不

    

      为了证明引用,写个例子

     var a=[];   //定义一个引用空数组的变量a
     var b=a;    //把a在内存中的地址  给b,此时它们指向的是同一个内存中的地址
     b[0]=1;      //b添加了一个值,由于它们引用了同一个地址,所以修改的是它们公用的内存,所以a也变了
     alert(a[0]);    //   1

    那么如果我们想要一个备份的数组怎么办,我们可以通过循环来完成数组赋值

     var a=["a","b","c"];
     var b=[];
     for(var i=0;i<a.length;i++){
         b[i]=a[i];
         }
    //此时我们修改b,a不会被修改,因为 a,b两个在内存中的地址不一样,"a","b","c"都是原始值,赋值时都是备份
      alert(a[0]+"   "+b[0]);  //复制完后
      b[0]="abc";    //开始修改
     alert(a[0]+"   "+b[0]); 

 

     下面我自己写了一段代码,只要记住,引用类型不复制值,每一次都是一个对象在内存中的地址的 指向,你就记清楚了

     var a=[1,2,3];
     var b=[];
     
     var c=[a,"a",3];
     var d=[];  //我们把c中的值复制给d
     
    // alert(c[0][0]);  //1,  变量c中的 第一个索引位置,即a变量,a变量是个数组,然后在a变量中的第一个索引位置,即1
     
     for(var i=0;i<c.length;i++){
         if(i==0){
    
             b=c[i];        //将c中的第一个索引的位置,即a在内存中的地址给b,此时公用一个地址
              
             d[i]=b;            //将b 放在d对象的  第一个索引的位置上,此时b和a还是公用的
         }else{
             d[i]=c[i];
             }
         }
        
     //这个时候 我修改 b,会怎么样,d中的第一个值中的会怎么样
     alert(b[0]);      //1
     b[0]=5;
     alert(a[0]);     //5
     alert(c[0][0]);  //5
     alert(d[0][0]);  //5

 

 

15.类型转换

   下面有一张表,可以参考一下

       image

 

例如:JavaScript期望使用一个数字,它将把给的值转换成数字,转换无意义,比如把abc字符转换成数字,这不可能的,就会返回NaN

       下面有些小例子,看看就领悟出来了

        10+”objects”             //会自动变成字符串 “10objects”,数字10将会自动转换成字符串,+号是连接字符串的

        ”7”*"4”                    //28,两个字符串均转换成 数字了,因为*代表乘号,代表一种运算,不像加号特殊

        var n=1-“x”;            //有减号在,x将被转换成数字,结果失败,当然无意义了,返回NaN,所以变量最终是NaN

        此时 n+”objects”        //n转换成字符串是NaN,所以最终返回 NaNobjects

 

原始值到对象的转换非常简单,通过调用 String()  、Number() 、Boolean()构造函数,即可转换为它们各自的包装对象,null和undefined例外,转换时无法正常转换

 

 

转换和相等性

由于JavaScript可以做灵活的类型转换,“==”相等运算符的含义也有变化

下面这些结果都是true

     alert(null==undefined);    //这两个值认为相等过的
     alert("0"==0);             //在比较之前字符串转换成数字
     alert(0==false);           //在比较之前布尔值转换成了数字
     alert("0"==false);    //在比较之前字符串和布尔值都转成了

 

后面我们讲解 “==”等于运算符在判断两个值是否相等时做了哪些类型转换,并同样介绍了“===”恒等运算符在判断相等时并未做任何类型转换。

注意:一个转换为另一个值并不意味着两个值相等

例如  alert(false==undefined);  //false

如果在期望使用布尔值的地方使用了undefined,它将会转换为false,但这并不表明undefined==false。

 

 

显示类型转换

 

尽管JavaScript可以自动做许多类型转换,但有时我们仍需做显示转换,或者只是为了代码更容易读

1.除了null和undefined之外的任何值都有toString()方法,这个方法的执行效果通常和String()方法的返回结果一样。

  javaScript中的某些运算符会做隐式的类型转换,比如特殊的 + 号,有时是运算,有时连接字符串的,此时它就会把不是字符串的转换成字符串,作为连接字符串的效果,还有!号,取布尔值的反

           x+””        //等价于String(x)

           +x          //等价于Number(x),也可以写成x-0

           !!x          //等价于Boolean(x),双感叹号

           Number(“3”)    // 3

           String(false)    //”false”      或者false.toString()

          Boolean([])      //true

           Object(3)         //new  Number(3)

 

2.关于 字符串转数字,数字转字符串,更高级的,十进制转2进制,8进制,16进制

var tenNumber=17;
var binary_string=tenNumber.toString(2);      //  "10001"
var otcal_string="0"+tenNumber.toString(8);     //转换成 "021"
var hex_string="0x"+tenNumber.toString(16);    //转换成 "0x11"
var summary="数字"+tenNumber+"转换成二进制是"+binary_string+";\n转换成八进制是"+otcal_string+";\n转换成十六进制是"+hex_string;
alert(summary);

3.处理财务,科学计数时候可能需要,下面的几个方法

var n=123456.789;
var a=n.toFixed(0);       //"123457"四舍五入,0代表不保留任何小数,那么同理1就代表保留1位小数
var b=n.toFixed(2);       //"123456.79"
var c=n.toFixed(5);        //"123456.78900"
 
//指数计数法,toExponential(参数),参数代表了,小数位有几位数字
var d=n.toExponential(1);     //  "1.2e+5" ,代表1.2乘以10的5次方
var e=n.toExponential(3);     //  "1.235e+5"
 
//指数计数法,toPrecision(参数),参数代表了,包括整数和小数部分一共要有几个有效数字
var f=n.toPrecision(4);       // "1.235e+5",这里是参数是4,代表了整数部分1个,加上小数部分3个,总共凑满4个有效数字
var g=n.toPrecision(7);       // "123456.8"   //参数超过了整数部分数字的个数
var h=n.toPrecision(10);      //"123456.7890"  //不足部分补0
    

    

4.parseInt()只解析整数,parseFloat() 整数和浮点数都解析

    var  dd=Number("12.14");
//    alert(dd);       // 12.14
    var d1=parseInt("3 blind mice");       //3
    var d2=parseFloat("3.14 meters")        //d2
    var d3=parseInt("-12.74");               //-12,不四舍五入的,只取整数部分
    var d4=parseInt("0xff");                // 255
    var d5=parseInt("-0xff");               //-255
    var d6=parseFloat(".1");                 //0.1
    var d7=parseInt(".1");                 //0
    var d8=parseInt(".1");                 //NaN,整数不能以点数开始
    var d9=parseFloat("$222.22");          //NaN,数字不能以$开

   

5.parseInt()第二个参数,指定数字的转换的基数,合法的范围是2~36

    var d10=parseInt("11",2);      // 3 (1*2+1*1)   相当于将十进制11转换成2进制
    var d11=parseInt("ff",16);     // 255 (15*16+15*1)   相当于转换成十六进制 
    var d12=parseInt("077",8);     // 63 (7*8+7*1)   相当于转换成8进制

 

 

 

6.对象转换成 原始值

    所有对象都将转换成true,对于包装对象也是的,new Boolean(false) 是一个对象而不是原始值,它将转换为true

     所有的对象都继承了两个转换方法

    1. toString():返回一个反应这个对象的字符串

         ({x:1,y:2}).toString()      //=> “[object object]”

       很多类定义了很多特定版本的toString()方法,例如 数组类的toString()方法将每个数组元素转换为一个字符串,在元素之间添加逗号后合并成结果字符串,函数类的toString()方法返回这个实现定义的表示方法,还有日期类,正则类什么的

    var tos1=[1,2,3].toString();    //1,2,3
    var tos2=(function(x){ f(x); }).toString();    //  function(x){ f(x); }
    var tos3=/\d+/g.toString();                    //   /\d+/g
    var toS4=new Date(2013,2,22).toString();       //  Fri Mar 22 2013 00:00:00 GMT+0800 (中国标准时间)     
    console.log(toS4);

     

    2.valueOf()

       这个方法的任务并未详细定义:如果存在任意原始值,它将默认将对象转换为表示它的原始值。

        对象是复合值,而且大多数对象无法真正表示一个原始值,因为默认的valueOf()方法简单的返回对象本身,而不是返回一个原始值。数组、函数和正则表达式简单地继承了这个默认方法,调用这些类型的是你的valueOf方法只是简单的返回对象本身,日期类定义的valueOf()方法会返回它的一个内部表示,1970年1月1日以来的毫秒数

       var d=new Date(2010,0,1);      //2010年1月1日

       alert(d.valueOf())                    //1262332800000

    原理太多不讲了,感兴趣的可以查一下关于 toString()和valueOf()

 

 

16. 变量声明

    

     1.使用var声明,不在乎什么类型,声明了一个变量,未初始化时,初始值都是undefined

       2.形式

             var i;

             var k=”22”;

             var a,b,c;

             var i=0,j=0,k=0;   

            for(var i=0;i<10;i++)console.log(i);           //当循环体只有1条语句时,花括号可以省略

            for(var i=0,j=10;j<10;i++,j—)console.log(i*j);

            for(var p in o)console.log(p);

     3. 编程语言分动态(类型)语言和静态(类型)语言,动态类型语言是指在 运行期间才做数据类型检查的语言。例如Python,Ruby,JavaScript等典型的动态类型语言。静态类型语言,它的数据类型是在编译期间检查的,也就是说在写程序时要声明所有变量的数据类型,C/C++,Java,C#等

      4.例如var i=10;i=”ten”;  在JavaScript中是合法的

      5. 使用var语句重复声明变量是合法无害的。如果重复声明带有初始化器,那么这就和一条简单的赋值语句没什么两样

          如果给一个未声明的变量赋值,这个不好的习惯会造成很多bug,你应该始终使用var来声明变量

 

17.变量作用域

 

     定义:一个变量的作用域是程序源代码中定义这个变量的区域。全局变量拥有全局作用域,在JavaScript代码中的任何地方都有定义的。然而在函数内声明的变量只在函数体内有定义。他们是局部变量,作用域是局部性的。函数参数是局部变量,它们只在函数体内有定义。

      1.在函数体内,局部变量优先级>同名的全局变量。如果在函数内声明的一个局部变量或者函数参数中带有的变量和局部变量重名,那么全局变量就被局部变量所遮盖

var scope="global";
function checkscope(){
    var scope="local";
    return scope;
    }
alert(checkscope());      //local

 

    2. 尽管在全局作用域编写代码时可以不写var语句,但声明局部变量时则必须使用var语句

scope="scope";
function checkscope2(){
    scope="local";
    myscope="local";
    return [scope,myscope];
    }
alert(checkscope2().toString());     //local,local

 

     3.函数定义是可以嵌套的,每个函数都有自己的作用域 ,估计很少有人这样去写

var scope="global scope"; //全局
function checkscope3(){
     var scope="local scope";
 
      function nested(){
          var scope="nested scope";
          return scope;
          }
 
      return nested();
    }
alert(checkscope3());       //嵌套作用域
 
 

18.函数作用域和声明提前

    在一些类似C语言的编程语言中,花括号类的每一段代码都具有各自的作用域,而且变量在声明他们的代码段之外是不可见的,我们称为块级作用域,Js中是没有的。Js有的是 函数作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的

    例 1                    

 

function test(o){
    var i=0;
    if(typeof o =="object"){
        var j=0;
        for(var k=0;k<10;k++){
            console.log(k);
            }
        console.log(k);    //k已经定义了,输出10,这个在C#或者java中肯定不可以的
        }
    console.log(j);         //0,j已经定义了, var j=0
    }
    
test([1,2,3]);
 
总结:JavaScript的函数作用域是指在函数内声明的所有变量在函数体内始终可见的。有意思的是,这意味着变量在声明致歉甚至已经可用。JavaScript这个特性被称为  声明提前(hoisting)
     即JavaScript函数里声明的所有变量(但不涉及赋值)都被“提前”至函数体的顶部。
声明提前这步骤是在JavaScript引擎的“预编译”时进行的,是在代码开始运行之前
 
 
 
    例 2                   
 
var scope="global";
function f1(){
    console.log(scope);    
    }
 
function f2(){
    console.log(scope);       //输出 "undefined"  而不是 "global"
    var scope="local";        //变量本身在函数体内任何地方均是有定义的
    console.log(scope);    //输出 “local”
    }
 
f2();

     image

上面的f2方法代码等同于

function f3(){
    var scope;
    console.log(scope);       //输出 "undefined"  而不是 "global"
    scope="local";
    console.log(scope);    //输出 “local”
    }

函数体内,声明提前,结果优先级高过了同名的全局变量。

 

所以在 具有 块级作用域 的编程语言中,在狭小的作用域里让变量声明和使用变量的代码尽可能靠近彼此,这个变成习惯非常不错。但在JavaScript没有块级作用域,因此程序员 特意将变量声明放在函数体顶部。这样做使他们的源代码非常清晰地反映了真实的变量作用域。

 

JavaScript全局变量是全局对象的属性,这是在ECMAScript规范中强制规定的。对于局部变量没有如此规定。JavaScript可以允许使用this关键字来应用全局对象,却没有方法可以引用局部变量中存放的对象。

var truevar=1;        //声明一个不可删除的全局变量
fakevar=2;             //创建一个全局对象的一个不可删除的属性
this.fakevar2=3;      //创建一个全局对象的一个不可删除的属性
 
delete truevar;            //false,变量并没有被删除
delete fakevar;           //true,变量被删除
delete this.fakevar2;    //true,变量被删除
 
console.log(truevar);
console.log(fakevar);
console.log(this.fakevar2);

 

image

 

19.作用域链

  在大大小小的一个个作用域里面,就组成了一个作用域链,比如,当JavaScript需要查找x的值的时候,它从链中的第一个对象开始查找。如果这个对象有一个名为x的属性,那就直接使用了,查找结束

第一个对象没有不存在名为x的属性,JavaScipt会继续查找链上的下一个对象。以此类推,如果作用域链上没有任何一个对象含有属性x,那么就认为这段代码的作用域链上不存在x,并最终抛出一个引用错误(ReferenceError)异常。

  在JavaScript的最顶层代码中,作用域链由一个全局对象组成。在不包含嵌套的函数体内,作用域链上有两个对象,第一个是定义函数参数和局部变量的对象,第二个是全局对象。

  在一个嵌套的函数体内,作用域链上至少有3个对象。理解对象链非常重要。当定义一个函数时,它实际上保存一个作用域链。

image

 

 

作用域的概念对于理解with语句是非常有帮助的,对理解 闭包的概念也至关重要

 

相关资源下载: http://download.csdn.net/download/yangyanghaoran/5168489

 

 

额外赠送:

   Win7小技巧--将资源管理器 默认打开 改成 我的电脑,手动点点设置,就可完成

 

 第一步:右击 资源管理器展开,再右击 打开后的列表中 红色圈住部分,点击属性

  

   

    第二步:将红色区域,目标  右边的文本框 代码改成  %SystemRoot%\explorer.exe /e,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}

    

快捷键右侧的  文本框  按下  win+E键

 

第三步:点击确定。

第四步:你在单击一下资源管理器,默认就打开我的电脑了,而不再是不常用的 库了


posted @ 2013-03-22 08:27  AYUI框架  阅读(2149)  评论(10编辑  收藏  举报