标签:
一 简介
 1.JavaScript是一种脚本语言,由LiveScript改名而来,Netscape公司为了推广这个脚本语言,利用了java的知名度,两者并没有什么关系。JavaScript是一种基于客户端浏览器的,基于对象、事件驱动式的脚本语言。
 2.java和javaScript的关系
 (1)完全是两个不同的产品,Java是Sun公司推出的面向对象的程序设计语言;JaaScript是Netscape公司的产品,目的是为了拓展Netscape浏览器功能。javaScript是一种可以嵌入Web页面中的解释性语言。
 (2)Java语言最小的程序单位是类定义,JavaScript中充斥着大量函数。
 (3)Java是强类型变量语言,所有的变量必须先声明,才可以使用,所有的变量都有其固定的数据类型;JavaScript是弱类型变量语言,变量在使用前无需声明,由解释器在运行时检查其数据类型。
 
3.在实际的使用过程中,还有另一种脚本语言:JScript,由Microsoft公司开发。由于早期JScript和javaScript差异较大,
程序员要为两种浏览器分别编写脚本,后来就诞生了ECMAScript,这是一个国际标准化的JavaScript版本,现在的主流浏览器都会支持这个版
本。
 二 变量
 1.全局变量和局部变量
 在JavaScript中同一个变量可以反复赋值,而且可以是不同类型的变量,但是要注意只能用var声明一次。这种变量类型不固定的语言称为动态语言,与之对应的静态语言,如java,赋值时类型不匹配会报错。
 全局变量:(1)在方法外部声明的变量(2)方法内部,没有加var关键字声明的变量
 局部变量:方法内部,使用var声明的变量
 <script type="text/javascript">
 var a=3; //全局变量
 function test(){
 var a=2; //局部变量
 alert(a);
 }
 test();
 </script>
 结果:2
 如果注释掉var a=2;
 <script type="text/javascript">
 var a=3; //全局变量
 function test(){
 // var a=2; //局部变量
 alert(a);
 }
 test();
 </script>
 结果:3
 若将程序改为:
 <script type="text/javascript">
 function test(){
 c=5; //相当于全局变量
 }
 alert(c);
 test();
 </script>
 结果为:c is not defined
 c虽然是全局变量,但是要先执行函数test(),才能执行到c。也就是说,javascript是由上而下执行的。
 2.变量提升
 JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:
 function foo() {
     var x = ‘Hello, ‘ + y;
     alert(x);
     var y = ‘Bob‘;
 }
 foo();
 语句var x = ‘Hello, ‘ + y;并不报错,原因是变量y在稍后申明了。但是alert显示Hello, undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。
 对于上述foo()函数,JavaScript引擎看到的代码相当于:
 function foo() {
     var y; // 提升变量y的申明
     var x = ‘Hello, ‘ + y;
     alert(x);
     y = ‘Bob‘;
 }
 由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。最常见的做法是用一个var申明函数内部用到的所有变量。
 3.变量的作用范围
 JavaScript的变量没有块范围。
 <script type="text/javascript">
 function test(o){
      var i=0;
      if(typeof o=="object"){
           //定义变量j,变量j的作用范围是整个函数内,而不是if块内
           var j=5;
           for(var k=0;k<10;k++){
                //k的作用范围是整个函数内,而不是循环体内
                document.write(k);
           }
      }
      //即使出了循环体,k的值依然存在
      alert(k+"\n"+j);
 }
 test(document);
 </script>
 结果:10   5
 再如:
 <script type="text/javascript">
 //定义全局变量
 var scope="全局变量";
 function test(){
      //全局变量被局部变量覆盖,而此时scope局部变量尚未赋值,故此处输出undefined
      document.writeln(scope+"<br />");
      //定义局部变量,其作用范围为整个函数内
      var scope="局部变量";
      document.writeln(scope+"<br />");
 }
 test();
 </script>
 结果:undefined 局部变量
 三 数据类型
 1.基本数据类型:Number,Boolean,String,Undefined,Null
 Number:整数,小数,NAN,Infinity(正无穷),-Infinity(负无穷)
 Undefined:表示变量声明但是未赋值
 Null:表示一个空的对象引用
 注意:NaN是一个特殊的数值,它是Not a Number三个单词的首字母,表示非数。NaN==NaN返回false。isNaN()函数就专门用来判断某个变量是否为NaN
 例:var a=1/0;并不会报错,会返回Infinity
 2.复合类型
 复合类型是由多个基本数据类型组成的数据体,JavaScript中的复合数据类型有大致3种:Object:对象;Array:数组;Function:函数
 对象:JavaScript是基于对象的脚本语言,它提供了大量的内置对象供用户使用。除了Object外,还有如下常用的内置类:
 Array  Date  Error  Function  Math  Number  Object  String
 数组:数组长度可变,同一数组中的元素类型可以互不相同,访问数组元素时不会越界,访问并未赋值的数组元素时,该元素的值为undefined
 函数:JS的函数声明中,参数列表不需要数据类型声明,函数返回值也不需要数据类型声明,函数可以单独存在,无需属于任何类,函数必须要用function关键字定义
 3.typeof和instanceof
 typeof用来判断数据变量的数据类型,instanceof用来判断某个变量是否为指定类的实例。
 如:
 var a=5;
 alert(typeof(a));   //number
 var b=[1,2];
 alert(b instanceof Array);   //true
 四 数组
 js数组类似于java容器,长度可变,元素类型也可以不同
 <script type="text/javascript">
     var arr=[1,false];
     var result=arr.push(2,true,"abc");
     alert(arr);
     alert(result);
 </script>
 结果为:1,false,2,true,abc            5
 其中,push()函数会向数组中添加元素,并会返回新数组的长度
 <script type="text/javascript">
     var arr=[1,false,2,"dfr"];
     var obj=arr.pop();
     alert(arr);
     alert(obj);
 </script>
 结果:1,false,2                   dfr
 其中,pop()函数可以从数组的尾部移除一个元素,并返回移除的元素值
 shift()函数从头部移除一个元素,unshift()函数从头部插入多个元素,并返回新数组的长度
 <script type="text/javascript">
     var arr=[1,2,4,6,3];
     arr.splice(1, 2,3,4,5);
     alert(arr);
 </script>
 结果:1,3,4,5,6,3
 其中,splice()的第一个参数表示起始位置,第二个参数表示截取的个数,第三个参数以后表示要追加的新元素
 若是只有两个参数,arr.splice(1,2);结果为:1,6,3
 程序若改为:
 <script type="text/javascript">
     var arr=[1,2,4,6,3];
     arr.slice(2,4);
     alert(arr);
 </script>
 结果:1,2,4,6,3
 slice()函数截取范围:左闭右开区间,不操作数组本身,返回截取的内容,而splice方法会操作数组本身
 修改程序:
 <script type="text/javascript">
     var arr=[1,2,4,6,3];
     var result=arr.slice(2,4);
     alert(result);
 </script>
 结果:4,6
 <script type="text/javascript">
     var arr1=[1,2,3];
     var arr2=[2,3,4];
     var result=arr1.concat(arr2);
     alert(result);
 </script>
 结果:1,2,3,2,3,4
 同理,concat()合并粘贴,不操作数组本身
 <script type="text/javascript">
     var arr1=[1,2,3];
     var result=arr1.join(‘-‘);
     alert(arr1)
     alert(result);
 </script>
 结果为:1,2,3       1-2-3
 join()方法在每个元素之间加入内容,也不操作数组
 sort()方法正序排序,reverse()方法倒序排序
 五 strict模式
 
javaScript在设计之初,为了方便初学者学习,并不强制要求用var申明变量。这个设计错误带来了严重的后果:如果一个变量没有通过var申明就
被使用,那么该变量就自动被申明为全局变量。在同一个页面的不同的JavaScript文件中,如果都不用var申明,恰好都使用了变量i,将造成变量i
互相影响,产生难以调试的错误结果。
 
为了修补JavaScript这一严重设计缺陷,ECMA在后续规范中推出了strict模式,在strict模式下运行的JavaScript代码,强
制通过var申明变量,未使用var申明变量就使用的,将导致运行错误。启用strict模式的方法是在JavaScript代码的第一行写上: 
‘use strict‘;
 这是一个字符串,不支持strict模式的浏览器会把它当做一个字符串语句执行,支持strict模式的浏览器将开启strict模式运行JavaScript。
 六 函数
 JavaScript是一种基于对象的脚本语言,JavaScript代码复用的单位是函数。函数可以独立存在,JS中的函数完全可以作为一个类使用,并且它还是该类唯一的构造器。函数本身也是一个对象,它是Function实例。
 1.函数的定义
 (1)定义命名函数
 格式:function 函数名(x){ 函数执行体; }
 举例:
 <script type="text/javascript">
 hello(‘lly‘);
 function hello(name){
      alert(name+",hello");
 }
 </script>
 函数的最大作用是提供代码复用,将需要重复的代码块定义成函数,可以提供更好的代码复用。
 上例中可以看出,javascript允许先调用函数,然后再定义该函数。在不同的<script>中,必须要先定义,然后再调用。
 实际上采用命名函数的方式,代码的可读性并不好,因为在定义函数时也得到了一个对象。
 (2)定义匿名函数
 var 函数名=function(x){ 函数执行体; };
 程序使用function关键字定义一个函数对象,再将这个对象复制给变量,以后就可以通过该变量来调用这个函数。很多优秀的JS源代码,如jQuery,Prototype.js等等,都是采用这种方式来定义函数的。
 这种方法说明,在javascript中,函数就是一种对象,也就是说,函数也是一种数据类型,参数列表相当于函数的入口,return相当于函数的出口。
 如:
 var abs = function (x) {
     if (x >= 0) {
         return x;
     } else {
         return -x;
     }
 };
 abs(2);
 上述两种定义完全等价,注意第二种方式按照完整语法需要在函数体末尾加一个;,表示赋值语句结束。
 2.函数  方法  对象  类
 函数是javascript编程里非常重要的一个概念,当使用javascript定义一个函数后,实际上可以得到以下4项:
 函数:像java的方法一样,这个函数可以被调用。
 对象:定义一个函数时,系统会创建一个对象,该对象是Function的实例。
 方法:定义一个函数时,该函数通常会附加给某个对象,作为该对象的方法。
 类:定义函数的同时,也得到了一个与函数同名的类。
 如:
 <script type="text/javascript">
 var hello=function(name){
      return name+",hello";
 }
 alert("hello是否是Function对象:"+(hello instanceof Function)+"\nhello是否是Object对象:"+(hello instanceof Object));
 alert(hello);
 </script>
 结果:true true 直接输出函数本身,则会输出函数的源代码。
 由上可知,在定义一个函数后,有两种方式来调用函数:
 (1)直接调用:总是返回该函数体内最后一条return语句的返回值,若没有return则没有返回值。
 (2)使用new关键字调用:这种方式总有一个返回值,返回值就是一个JavaScript对象。
 <script type="text/javascript">
 function Person(name,age){
      //被this修饰的关键字不再是局部变量,而是该函数的实例属性
      this.name=name;
      this.age=age;
      this.info=function(){
           document.writeln("my name is:"+this.name);
           document.writeln("my age is:"+this.age);
      };
 }
 var p=new Person("lyy",20);
 p.info();
 </script>
 由上可知,js定义的函数可以附加到某个对象上,作为该对象的方法。实际上,如果没有明确指定将函数附加到哪个对象上,则默认将其附加到window对象上,作为window对象的方法。
 <script type="text/javascript">
      //直接定义一个函数,不指定该函数属于哪个对象
      var hello=function(name){
           document.writeln(name+‘hello‘);
      }
      //window调用hello函数
      window.hello(‘lyy‘);
     
      //定义一个对象
      var p={
           walk:function(){
                document.writeln("walk....");
           }
      }
      p.walk();
 </script>
 3.函数的实例属性和类属性
 js中函数不仅仅是一个函数,还是一个类,该函数还是此类唯一的构造器,调用函数时使用new关键字可以返回一个Object对象,该Object不是函数的返回值,而是函数本身产生的对象。因此在JS中,不仅有局部变量,还有实例属性和类属性。
 局部变量:以普通方式声明的变量,包括以var和不加任何前缀声明的变量。
 实例属性:以this前缀声明的变量。
 类属性:以函数名前缀修饰的变量。
 其中,实例属性和类属性是面向对象的概念:实例属性是属于单个对象的,因此必须通过对象来访问;类属性是属于整个类(即函数)本身的,因此必须通过类(函数)来访问。
 <script type="text/javascript">
 function Person(name,national){
      this.name=name;
      var a=0;
      Person.national=national;
 }
 var p=new Person("lyy",‘‘China");
 document.writeln(p.name+Person.national+p.a)
 </script>
 结果:lyy China undefined
 4.调用函数
 JavaScript提供了三种方式来调用函数:
 (1)直接调用:以函数附加的对象作为调用者,在函数后括号内传入参数来调用函数,如上面的p.walk();这种方式也是最常见的方式
 (2)以call()方法调用函数
 直接调用函数比较简单,但是不够灵活,有时在调用函数时还需要动态的传入一个函数引用,为了动态调用函数,就需要使用call方法。
 调用者.函数(参数列表)=函数.call(调用者,参数列表)
 <script type="text/javascript">
      //定义一个each函数
      var each=function(array,fn){
           for(var index in array){
                //以window为调用者来调用fn函数,将index,array[index]作为参数传递给fn函数
                fn.call(null,index,array[index]);
           }
      }
      //调用each函数
      each([2,3,4,5],function(index,ele){
           document.write("第"+index+"个元素是:"+ele);
      });
 </script>
 (3)以apply()方法调用函数
 apply()方法和call()方法都可以动态的调用函数,功能基本相似,在用法上有以下区别:
 
通过call()调用函数时,必须在括号中详细的列出每个参数;通过apply()动态调用函数时,可以在括号中以arguments来代表所有参数。它
只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数,arguments类似Array但它不是一个Array。
 function foo(x) {
     alert(x); // 10
     for (var i=0; i<arguments.length; i++) {
         alert(arguments[i]); // 10, 20, 30
     }
 }
 foo(10, 20, 30);
 实际上arguments最常用于判断传入参数的个数。你可能会看到这样的写法:
 // foo(a[, b], c)
 // 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
 function foo(a, b, c) {
     if (arguments.length === 2) {
         // 实际拿到的参数是a和b,c为undefined
         c = b; // 把b赋给c
         b = null; // b变为默认值
     }
     // ...
 }
 要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。
 5.函数的独立性
 在定义函数时可以将函数定义为某个类的方法或某个对象的方法,但是实际上,函数是独立的,并不属于其他类或对象。
 <script type="text/javascript">
      function Person(name){
           this.name=name;
           this.info=function(){
                alert("name是:"+this.name);
           }
      }
      var p=new Person("lyy");
      p.info();  //name是:lyy
      var name="lulu";
      p.info.call(window);  //name是:lulu
 </script>
 6.函数的参数传递
 基本类型:值传递。当通过实参调用函数时,传入函数里的并不是实参本身,而是实参的副本,因此在函数中修改参数值并不会影响到实参。
 <script type="text/javascript">
      function change(arg1){
           arg1=10;
           document.write("函数执行中的arg1的值为:"+arg1);
      }
      var x=5;
      document.write("函数调用前的arg1的值为:"+arg1);
      change(x);
      document.write("函数调用后的arg1的值为:"+arg1);
 </script>
 函数调用前的arg1的值为:5
 函数执行中的arg1的值为:10
 函数调用后的arg1的值为:5
 复合类型:值传递。
 <script type="text/javascript">
      function changeAge(person){
           person.age=10;
           document.write("函数执行中person的age值为:"+person.age);
           person=null;
      }
      var person={age:5};
      document.write("函数调用前person的age值为:"+person.age);
      changeAge(person);
      document.write("函数调用后person的age值为:"+person.age);
      document.write("person对象为:"+person);
 </script>
 函数调用前person的age值为:5
 函数执行中person的age值为:10
 函数调用后person的age值为:10
 person对象为:[object Object]
 
注意:函数最后一行将person对象直接赋值为null,但是在函数执行结束后,person依然是一个对象,而不是null,这说明person本身
并未传入到changeAge()函数中,传入函数的依然是副本。复合类型的变量本身并未持有对象本身,只是一个引用,该引用指向实际的
javascript对象。当把person复合类型的变量传入changeAge()函数中时,传入的依然是person对象的副本,只是该副本和原
person变量指向同一个javascript对象。
 七 对象
 1.对象
 由于javascript的函数定义不支持继承语法,因此javascript没有完善的继承机制,所以我们习惯上称javascript是基于对象的脚本语言。
 javascript中的对象本质上是一个关联数组,或者说更像是java里的Map数据结构,由一组key-value对组成,这里的value,不仅可以是值(包括基本类型和复合类型),此时的值是函数的属性;还可以是函数,此时的函数就是该对象的方法。
 当访问对象的属性时,可以使用obj.propName的形式,也可以采用obj[propName]的形式,有时必须采用这种形式,如:
 <script type="text/javascript">
      function Person(name,age){
           this.name=name;
           this.age=age;
           this.info=function(){
                alert(‘info method!‘);
           }
      }
      var p=new Person(‘lyy‘,20);
      for(propName in p){
           document.writeln(‘p对象的‘+propName+‘属性值为:‘+p[propName]);
      }
 </script>
 这里必须用p[propName],因为如果用p.propName,会直接访问p对象的propName属性,但是实际上并没有propName属性。
 2.继承和prototype
 javascript虽然也支持类、对象的概念,但是并没有继承的概念,只能通过特殊的方式来扩展原有的javascript类。
 javascript是一种动态语言,它允许自由的为对象增加属性或方法,当程序为对象的某个不存在的属性赋值时,就可以认为是在为该对象增加属性。
 <script type="text/javascript">
 function Person(name,age){
      //被this修饰的关键字不再是局部变量,而是该函数的实例属性
      this.name=name;
      this.age=age;
      this.info=function(){
           document.writeln("my name is:"+this.name);
           document.writeln("my age is:"+this.age);
      };
 }
 var p1=new Person("lyy",20);
 p1.info();
 var p2=new Person("lulu",23);
 p2.info();
 </script>
 上面这种为Person类定义info方法相当不好,主要有两个原因:
 性能低下:每次创建Person实例时,程序依次向下执行,每次都会创建一个新的info函数,会造成系统内存泄漏,引起性能下降。
 使得info函数中的局部变量产生闭包:闭包会扩大局部变量的作用域,使得局部变量一直存活到函数之外的地方。
 <script type="text/javascript">
 function Person(){
      var locVal="lyy";
      this.info=function(){
           //此处形成闭包
           document.writeln("locVal的值为:"+locVal);
           return locVal;
      };
 }
 var p=new Person();
 var val=p.info();
 //输出val返回值,该返回值就是局部变量locVal
 alert(val);
 </script>
 
程序的最后一行可以发现,即使离开了info函数,程序也可以访问到局部变量的值。为了避免这种情况,通常不建议在函数定义中直接为该函数定义方法,而是
建议使用prototype属性。javascript的所有类都有一个prototype属性,当我们为javascript类的prototype属
性增加函数、属性时,可以视为对原有类的扩展。增加了prototype属性的类继承了原有的类,这就是javascript所提供的伪继承机制。
 <script type="text/javascript">
 function Person(name,age){
      //被this修饰的关键字不再是局部变量,而是该函数的实例属性
      this.name=name;
      this.age=age;
      this.info=function(){
           document.writeln("my name is:"+this.name);
           document.writeln("my age is:"+this.age);
      };
 }
 var p1=new Person("lyy",20);
 p1.info();
 Person.prototype.walk=function(){
      document.writeln(this.name+‘慢慢走‘);
 }
 var p2=new Person(‘lulu‘,23);
 p2.info();
 p2.walk();
 //此时p1也具有了walk方法
 p1.walk();
 </script>
 
上面的程序实际上是用prototype为Person类增加了一个walk方法,这样会让所有的Person实例共享一个walk方法,而且该walk
方法还不在Person函数之内,因此不会产生闭包。注意:javascript并没有提供真正的继承,当通过某个类的prototype属性动态的增加
属性或方法时,其实质是对原有类的修改,并不是产生一个新的子类。
 <script type="text/javascript">
      Array.prototype.indexof=function(obj){
           var result=-1;
           for(var i=0;i<this.length;i++){
                if(this[i]==obj){
                     result=i;
                     break;
                }
           }
           return result;
      }
      var attr=[4,5,7,-2];
      alert(arr.indexof(-2));
 </script>
 3.创建对象
 主要有3种方式:
 (1)使用new关键字调用构造器创建对象
 <script type="text/javascript">
 function Person(name,age){
      this.name=name;
      this.age=age;
      this.info=function(){
           document.writeln("my name is:"+this.name);
           document.writeln("my age is:"+this.age);
      };
 }
 var p1=new Person("lyy",20);
 p1.info();
 </script>
 (2)使用Object直接创建对象
 <script type="text/javascript">
      var myObj=new Object();
      myObj.name="lyy";
      myObj.age="20";
      myObj.info=function abc(){
           document.writeln("my name is:"+this.name);
           document.writeln("my age is:"+this.age);
      }
      myObj.info();
 </script>
 (3)使用JSON语法创建对象
 JSON:JavaScript Object Notation,使用JSON可以避免书写函数,也可以避免使用new关键字,可以直接创建一个javascript对象。
 person={
      name:‘lyy‘,
      age:20,
      info:function(){
           document.writeln("my name is:"+this.name);
           document.writeln("my age is:"+this.age);
      }
      schools:[‘小学‘,‘中学‘,‘大学‘],
      parents:[{name:‘father‘,age:60,address:‘江苏‘},{name:‘mother‘,age:58,address:‘上海‘}]
 }
标签:
原文地址:http://www.cnblogs.com/lyy-2016/p/5944555.html