javascript碎碎念(面向对象备忘)

对象:在 JavaScript 中,对象分为两种。

一种可以称为“普通对象”,就是我们所普遍理解的那些:数字、日期、用户自定义的对象(如:{})等等。

还有一种,称为“方法对象”,就是我们通常定义的 function

自定义对象:

被称为JavaScript Object Notation(缩写JSON)的形式,翻译为中文就是“JavaScript对象表示法”。
    JSON为创建对象提供了非常简单的方法。例如,
    创建一个没有任何属性的对象:

    var o = {};

方法对象:

第一种写法

function MyFunc() {};         //定义一个空函数
    var anObj = new MyFunc();  //使用new操作符,借助MyFun函数,就创建了一个对象

第二种写法

function MyFunc(){};
    var anObj = {};     //创建一个对象
    MyFunc.call(anObj); //将anObj对象作为this指针调用MyFunc函数

理解 JavaScript先用new操作符创建了一个对象(anObj),紧接着就将这个对象(anObj)作为this参数调用了后面的函数(MyFunc())。

原型prototype:

话说每一个方法对象被创建时,都会自动的拥有一个叫 prototype 的属性。这个属性并无什么特别之处,它和其他的属性一样可以访问,可以赋值。不过当我们用 new 关键字来创建一个对象的时候,prototype 就起作用了:它的值(也是一个对象)所包含的所有属性,都会被复制到新创建的那个对象上去。

也可以这么说,prototype提供了一群同类对象共享属性和方法的机制。

下面是一个例子:

   function Person(name)
    {
        this.name = name;   //设置对象属性,每个对象各自一份属性数据
    };
    
    Person.prototype.SayHello = function()  //给Person函数的prototype添加SayHello方法。
    {
        alert("Hello, I'm " + this.name);
    }

    var BillGates = new Person("Bill Gates");   //创建BillGates对象
    var SteveJobs = new Person("Steve Jobs");   //创建SteveJobs对象

    BillGates.SayHello();   //通过BillGates对象直接调用到SayHello方法
    SteveJobs.SayHello();   //通过SteveJobs对象直接调用到SayHello方法

    alert(BillGates.SayHello == SteveJobs.SayHello); //因为两个对象是共享prototype的SayHello,所以显示:true

继承

原型模型需要一个构造函数来定义对象的成员,而方法却依附在该构造函数的原型上。大致写法如下:

//定义构造函数
    function Person(name)
    {
        this.name = name;   //在构造函数中定义成员
    };
    //方法定义到构造函数的prototype上
    Person.prototype.SayHello = function()
    {
        alert("Hello, I'm " + this.name);
    };    
    //子类构造函数
    function Employee(name, salary)
    {
        Person.call(this, name);    //调用上层构造函数
        this.salary = salary;       //扩展的成员
    };
    //子类构造函数首先需要用上层构造函数来建立prototype对象,实现继承的概念
    Employee.prototype = new Person()   //只需要其prototype的方法,此对象的成员没有任何意义!
    
    //子类方法也定义到构造函数之上
    Employee.prototype.ShowMeTheMoney = function()
    {
        alert(this.name + " $" + this.salary);
    }; 
    var SteveJobs = new Employee("Steve Jobs", 1234);
    SteveJobs.SayHello();
    SteveJobs.ShowMeTheMoney();

 

原型类模型虽然不能模拟真正的私有变量,而且也要分两部分来定义类,显得不怎么“优雅”。不过,对象间的方法是共享的,不会遇到垃圾回收问题,而且性能优于“闭包”模型。正所谓“有失必有得”嘛。

    在原型模型中,为了实现类继承,必须首先将子类构造函数的prototype设置为一个父类的对象实例。创建这个父类对象实例的目的就是为了构成原型链,以起到共享上层原型方法作用。但创建这个实例对象时,上层构造函数也会给它设置对象成员,这些对象成员对于继承来说是没有意义的。虽然,我们也没有给构造函数传递参数,但确实创建了若干没有用的成员,尽管其值是undefined,这也是一种浪费啊。

我们已经知道,用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步:

第一步是建立一个新对象;

第二步将该对象内置的原型对象设置为构造函数prototype引用的那个原型对象;

第三步就是将该对象作为this参数调用构造函数,完成成员设置等初始化工作。

对象建立之后,对象上的任何访问和操作都只与对象自身及其原型链上的那串对象有关,与构造函数再扯不上关系了。换句话说,构造函数只是在创建对象时起到介绍原型对象和初始化对象两个作用。

那么,我们能否自己定义一个对象来当作原型并在这个原型上描述类,然后将这个原型设置给新创建的对象将其当作对象的类呢?我们又能否将这个原型中的一个方法当作构造函数,去初始化新建的对象呢?例如,我们定义这样一个原型对象:

//代码1
var Person =  //定义一个对象来作为原型类
    {
        Create: function(name, age)  //这个当构造函数
        {
            this.name = name;
            this.age = age;
        },
        SayHello: function()  //定义方法
        {
            alert("Hello, I'm " + this.name);
        },
        HowOld: function()  //定义方法
        {
            alert(this.name + " is " + this.age + " years old.");
        }
    };
然后
function anyfunc(){};           //定义一个函数躯壳
    anyfunc.prototype = Person;     //将原型对象放到中转站prototype
    var BillGates = new anyfunc();  //新建对象的内置原型将是我们期望的原型对象

代码2

var o = {}; // 我发现了一个东西。   
o.eat = function(){return "I am eating."}  // 我发现它会吃;   
o.sleep = function(){return "ZZZzzz..."}  // 我发现它会睡;   
o.talk = function(){return "Hi!"} // 我发现它会说话;   
o.think = function(){return "Hmmm..."} // 我发现它还会思考。   
  
var Human = new Function(); // 我决定给它起名叫“人”。   
Human.prototype = o; // 这个东西就代表了所有“人”的概念。   
 
var h = new Human(); // 当我发现其他同它一样的东西,   
alert(h.talk()) // 我就知道它也是“人”了!

Javascript的一种模块模式

全局变量是魔鬼。在YUI中,我们仅用两个全局变量:YAHOO和YAHOO_config。YUI的一切都是使用YAHOO对象级的成员或这个成员作用域内的变量。我们建议在你的应用程序也使用类似的规则。

  • 创建一个命名空间对象:如果你使用YUI,可以用YAHOO.namespace()方法: YAHOO.namespace("myProject");这分配了一个空的myProject对象,是YAHOO的一个成员(如 果myProject已存在的话,则不会被覆盖)。现在我们可以开始添加YAHOO.myProject的成员。
  • 对你的命名空间对象分配一个匿名函数返回值:
    YAHOO.myProject.myModule = (function () {
        return  {
          myPublicProperty: "我作为YAHOO.myProject.myModule.myPublicProperty被访问。";
          myPublicMethod: function () {
          YAHOO.log("我作为YAHOO.myProject.myModule.myPublicMethod被访问。");
        }
    };
    })(); 
    让我们来看看jquery是怎么做的

     

         (function() {
                Me = function() {
                    return new Me.prototype.init();
                }
                Me.fn= Me.prototype = {
                    init: function() {
                        return this;
                    },
                    showname: function() {
                        alert("Jane");
                    },
                    showage: function() {
                        alert(Infinity);
                    }
                }
                Me.fn.init.prototype = Me.fn;
            })();
            Me().showname();
            Me().showage();
  •  
    入口:
  • var jQuery = window.jQuery = window.$ = function(selector, context) { 
      return new jQuery.fn.init(selector, context);
      }

      上面的代码①可以看出$(xx)或Jquery(xx)得到不是真正的jQuery函数生成的对象,而是jQuery.fn.init函数生成的对象。也是就是jQuery的对象继承的是jQuery.fn.init的原型。jQuery.fn = jQuery.prototype={..}。我们基本上不用new jQuery(xx),而是直接jQuery(xx),就是采用了new jQuery(xx),先生成jQuery函数的对象,把原型中的继承下来,返回的也是jQuery.fn.init函数生成的对象。而jQuery函数的对象也抛弃了。可见给jQuery.prototype上增加方法的意义不大。同时也可以看出采用new jQuery(xx)的效率更低。jQuery.fn.init是通过jQuery.fn.init.prototype = jQuery.fn;来获得的。

    • posted @ 2010-03-25 20:02  MyCoolDog  阅读(287)  评论(0编辑  收藏  举报