日期:2014-05-16  浏览次数:20307 次

js函数、prototype属性、作用域重点总结

近看完了javascript面向对象基础技术专栏,现把其中比较重要的、易错的知识点做个总结

?

函数:

创建函数:
1,function f(x) {........}
2,var f = function(x) {......}
上面这两种形式都可以创建名为f()的函数,不过后一种形式可以创建匿名函数
函数定义时可以设置参数,如果传给函数的参数个数不够,则从最左边起依次对应,其余的用undefined赋值,如果传给函数
的参数多于函数定义参数的个数,则多出的参数被忽略.
区别为:1种方式定义的函数,对函数的调用用可以在它之前,
而2种方式对函数的调用必须出现在函数定义之后。

?

函数的prototype属性:
先来说明一点:每一个函数都包含了一个prototype属性,这个属性指向了一个prototype对象。

function Person(name,sex) {  //Person类的构造函数
        this.name = name;  
        this.sex = sex;  
    }  
   Person.prototype.age = 12;   //为Person类的prototype属性对应的prototype对象的属性赋值,  
                                                   //相当于为Person类的父类添加属性  
   Person.prototype.print = function() { //为Person类的父类添加方法
       alert(this.name+"_"+this.sex+"_"+this.age);  
   };  
  var p1 = new Person("name1","male"); //p1的age属性继承子Person类的父类(即prototype对象) 
   var p2 = new Person("name2","male");  
   p1.print();  //name1_male_12 
   p2.print();  //name2_male_12 
   p1.age = 34; //改变p1实例的age属性  
  p1.print();  //name1_male_34  
  p2.print();  //name2_male_12  
  Person.prototype.age = 22;  //改变Person类的超类的age属性  
  p1.print();  //name1_male_34(p1的age属性并没有随着prototype属性的改变而改变)  
  p2.print();  //name2_male_22(p2的age属性发生了改变)  
  p1.print = function() {  //改变p1对象的print方法  
        alert("i am p1");  
   }  
   p1.print();  //i am p1(p1的方法发生了改变)  
   p2.print();  //name2_male_22(p2的方法并没有改变)  

   Person.prototype.print = function() { //改变Person超类的print方法  
      alert("new print method!");  
   }  

   p1.print();  //i am p1(p1的print方法仍旧是自己的方法)  
   p2.print();  //new print method!(p2的print方法随着超类方法的改变而改变)

在JS中,当我们用new操作符创建了一个类的实例对象后,它的方法和属性确实继承了类的prototype属性,类的prototype属性中定义的方法和属性,确实可以被这些实例对象直接引用.但是,当我们对这些实例对象的属性和方法重新赋值或定义后,那么实例对象的属性或方法就不再指向类的prototype属性中定义的属性和方法,此时,即使再对类的prototype属性中相应的方法或属性做修改,也不会反应在实例对象身上.这就解释了上面的例子:
一开始,用new操作符生成了两个对象p1,p2,他们的age属性和print方法都来自(继承于)Person类的prototype属性.然后,我们修改了p1的age属性,后面对Person类的prototype属性中的age重新赋值(Person.prototype.age = 22),p1的age属性并不会随之改变,但是p2的age属性却随之发生了变化,因为p2的age属性还是引自Person类的prototype属性.同样的情况在后面的print方法中也体现了出来.

?

作用域:

?

var sco = "global";  //全局变量  
  function t() { 
       var sco = "local";  //函数内部的局部变量  
       alert(sco);         //local 优先调用局部变量 
  }  
  t();             //local  
  alert(sco);      //global  不能使用函数内的局部变量

在javascript中没有块级别的作用域,也就是说在java或c/c++中我们可以
用"{}"来包围一个块,从而在其中定义块内的局部变量,在"{}"块外部,这些变量不再起作用,
同时,也可以在for循环等控制语句中定义局部的变量,但在javascript中没有此项特性看如下例子:

?

function f(props) {  
        for(var i=0; i<10; i++) {}  
        alert(i);         //10  虽然i定义在for循环的控制语句中,但在函数  
                         //的其他位置仍旧可以访问该变量.  
       if(props == "local") {  
            var sco = "local";  
        alert(sco);   
        }  
        alert(sco);       //同样,函数仍可引用if语句内定义的变量  
   }  
   f("local");      //10  local   local

在函数内部定义局部变量时要格外小心:

?

var sco = "global";  
 function print1() {  
    alert(sco);   //global  
 }  
 function print2() {  
     var sco = "local";  
     alert(sco);   //local  
 }  
 function print3() {  
     alert(sco);   //undefined  
     var sco = "local";   
     alert(sco);   local  
 }  
   
 print1();  //global  
 print2();  //local  
 print3();  //undefined  local

前面两个函数都很容易理解,关键是第三个:第一个alert语句并没有把全局变量"global"显示出来,
而是undefined,这是因为在print3函数中,我们定义了sco局部变量(不管位置在何处),那么全局的
sco属性在函数内部将不起作用,所以第一个alert中sco其实是局部sco变量,从这个例子我们得出,
在函数内部定义局部变量时,最好是在开头就把所需的变量定义好,以免出错。

?

?

以上都是看完js基础系列后的总结,具体可以参看:http://www.iteye.com/wiki/Object_Oriented_JavaScript

?

?