Javascript面向对象编程

来源:互联网 发布:mac怎么关掉客人用户 编辑:程序博客网 时间:2024/05/29 14:54

1.模块:

    var someSharedValue = 10;      var myFunction = function(){ //do something }      var anotherImportantFunction = function() { //do more stuff }  
    事实上这段代码有很多毛病,不过我们会专注在讨论全局命名空间的污染问题上。这样的代码代码会把方法和变量都暴露在了全局中,我们需要将让这些数据与全局命名空间独立开来,我们将会采用模块模式(Module Pattern)来实现这个目的,模块中可以有很多不同的形式达到我们的目标,我会从最简单的方法开始说:匿名函数(Immediately Invoked Function Expression,简写为:IIFE):匿名函数是会立即执行的函数。
    (function(){          //do some work      })();  
    使用模块的目的:

在JS中我们都是在和各种作用域之中的函数打交道,所以如果我们想要创建一个作用域,就可以使用函数。匿名函数中的变量和方法的作用域仅仅在匿名函数中,就不会污染全局的命名空间,那么现在还需要考虑的一个问题是,我们要如何从外部取得那些在匿名函数作用域中的变量和方法呢?答案就是全局命名空间:将变量放入全局命名空间中,或者至少将作用变量与全局命名空间关联起来。
    想要在匿名函数外部调用匿名函数中的方法,我们可以将window对象传入匿名函数再将匿名函数中的函数或变量值赋值到这个window对象上。为了保证这个window对象的引入不会造成什么混乱,我们可以将widow对象作为一个变量传入我们的匿名函数。当做函数传入参数的方法同样适用于第三方库,甚至undefined这样的值。现在我们的匿名函数看起来是这样的:

    (function(window, $, undefined){          //do some work      })(window, jQuery);  
    现在我们有了一个会立即执行的方法,还有一个相对安全的执行上下文,其中还包含有window、$和undefined变量(这几个变量还是有可能在这个脚本被执行前就被重新赋值,不过现在的可能性要小的多了)。现在我们已经做得很好了:把我们的代码从全局环境下的一团混乱的局面中拯救了出来;降低了与其他在同一应用中使用的脚本的冲突可能性。

    任何我们想要从模块中获取的东西都可以通过window对象拿到。但是通常我不会直接将模块中的内容直接复制到window对象上(一般不会直接将Window传入匿名函数中),而是会用一些容器组织模块中的内容。在大部分语言中,我们将这些容器称为“命名空间”,在JS中我们可以用“对象”的方式来模拟。


2.命名空间:

    声明一个命名空间,将一个函数放入其中:

<pre name="code" class="javascript">window.myApp = window.myApp || {};  window.myApp.someFunction = function(){ };

    首先检查全局变量myApp是否已经被定义(是否在同一文件中或在另一文件)。如果是的话,那么使用现有的myApp全局对象,否则,创建一个名为myApp的空对象,这样我们就可以开始添加这个命名空间的内容,将各种函数,属性放入这个空间中,但是我们又不希望这些函数就随便的放在那里,而是希望将模块和命名空间联系在一起,如下:

(function(app, $, undefined){      //do some work  })(window.myApp = window.myApp || {}, jQuery); 
或者:
window.myApp = (function(app, $, undefined){      //do some work      return myApp;  })(window.myApp || {}, jQuery);  
    举例:

定义命名空间Namespace1中的构造函数,方法,属性等

(function (NameSpace1, $, undefined) {    NameSpace1.Person = function (first_name, last_name, middle_name) {        this.firstName = first_name;        this.lastName = last_name;        this.middleName = middle_name;        this.age = 20;        this.address = "";    };    //NameSpace1.Person.prototype.ShowName = function (title) {    //    alert(title + ":" + this.firstName + " " + this.middleName + " " + this.lastName + " " + this.age + " " + this.address);    //};    NameSpace1.Person.prototype = {        Initial: function () {            alert("Initial");        },        GetStr: function (str)        {            alert("GetStr: " + str);        }    }})(window.NameSpace1 = window.NameSpace1 || {}, jQuery);

调用命名空间Namespace1中的方法:

(function () {    var titles = {        firstTitle: "first title",        secondTtile: "second title"    }    var person = null;    var result = "";    $(document).ready(function () {        person = new NameSpace1.Person("Long", "xi", "zhu");        person.age = 24;        person.address = "海淀黄庄";        //person.ShowName(titles.firstTitle);        person.Initial();        person.GetStr("test")    });})();

现在,我们不再是将window传入我们的模块中,我们将一个和window对象联系在一起的命名空间传入模块中。之所以使用’||’的原因是我们可以重复使用同一个命名空间,而不是每次需要使用命名空间的时候我们又要重新创建一个。许多包含有命名空间方法的库会帮你创建好空间的,或者你可以使用一些向namespace.js这样的工具来构建嵌套的命名空间。由于在JS中,每一个在命名空间中的项你都不得不指定它的命名空间,所以通常我都尽量不会去创建深度嵌套的命名空间。

3.类:(构造器)
    在JS中没有“类”这个概念,但是我们可以通过创建构造器来创建“对象”。假设现在我们要创建一系列Person对象,还需要传入姓、名和年龄,我们可以将构造器定义成下面这样(这部分代码应该放在模块之中):

    var Person = function(firstName, lastName, age){          this.firstName = firstName;          this.lastName = lastName;          this.age = age;      }             Person.prototype.fullName = function(){          return this.firstName + " " + this.lastName;      };  

    第一个函数,你会看到我们创建了一个Person构造器。我们用它来构造新的person对象。这个构造器需要3个传入参数,然后将这3个参数赋值到执行上下文中。我们也是通过这种方式获取到公有实例变量。这里也可以创建私有变量:将传入参数赋值到这个构造器中的局部变量。但是这么做以后,公有的方法就没法获取这些私有的变量了,所以你最好还是把它们都变成公有的。也可以把方法放在构造器中同时还能从外部获取到它,这样方法就能拿到构造器里的私有变量了,不过这么做的话又会出现一系列新的问题.

    第二个方法中我们使用了Person构造器的”原型”(prototype)。一个函数的原型就是一个对象,当你需要在某个实例上解析它所调用到的字段或者函数时你需要遍历这个函数上所有的实例。所以这几行代码所做的就是创建一个fullName方法的实例,然后所有的Person的实例都能直接调用到这方法,而不是对每个Person实例都添加一个fullName方法,造成方法的泛滥.也可以在构造器中用this.fullName = function() { … }的方式定义fullName,但这样每一个Person实例都会有fullName方法的副本,这不是我们希望的。

   创建Person实例:

    var person = new Person("Justin", "Etheredge");      alert(person.fullName());  
    我们也可以创建一个继承自Person的构造器:Spy构造器,我们会创建Spy的一个实例,不过只会声明一个方法:

var Spy = function(firstName, lastName, age){      this.firstName = firstName;      this.lastName = lastName;      this.age = age;  };  Spy.prototype = new Person();     Spy.prototype.spy = function(){      alert(this.fullName() + " is spying.");     }     var mySpy = new Spy("Mr.", "Spy", 50);  mySpy.spy(); 
    正如你所看到的,我们创建了一个和Person很相似的构造器,但是它的原型是Person的一个实例。现在我们又添加上一些方法,使得Spy的实例又可以调用到Person的方法,同时还能直接取得Spy中的变量。




0 0