zoukankan      html  css  js  c++  java
  • 对象和原型(上)

       面向对象是javascript核心内容之一,今天就来讨论对象和原型.

        首先讨论创建对象几种常见的方式:

      (1) 最经典,最简单的方法.利用object

          var o=new Object();//创建对象;

         o.name='jack';//添加属性

        o.sayName=function(){alert(this.name);}//添加方法;

        点评:这种方法明显不适合创建多个对象。

     (2)对象字面量形式:注意语法格式

        var o={

        name:'jack',

        sayName:function(){alert(this.name);}

    }

     

        (3)一种设计模式 ‘工厂模式’

       function  createObject(name){

         var o=new Object();

          o.name=name;

         o.sayName=function(){alert(this.name);}

         return o;

    }

          var obj=createObject('jack');   //创建对象

          alert(obj instanceof Object) //ture

         alert(obj instanceof createObject);//false;

          alert(type obj )//Object

     点评: 这种方式不难理解; 就是利用函数初始化一个Object对象,可以创建多个对象;

     缺点:无法判断对象的具体类型, 都是object对象。

        (4)  构造方法

             function Person(name){

           this.name=name;

          this.sayName=function(){alert(this.name);}

    }

          var o=new Person('jack');//创建对象;

           alert(o.name);//访问属性

           o.sayName();//访问方法;

           alert(o instanceof Person);//true

           alert(o instanceof Object);//true

           alert(type o);  //object

         那么 这种构造方法是如何创建对象的?     

         var o=new Person('jack');//创建对象;  

         这时调用构造方法,同时自动创建(底层,看不见) var o=new Object();然后 this=o; 我们知道此时this就代表对象了,创建该对象的属性和方法(执行代码); 返回this对象(看不见);

        我们的o接受this的引用,指向了Object对象,同时也就可以访问属性和方法了! 

     

        4 构造方法结合原型------"默认"模式.

          我们知道通过构造函数创建对象是有一弊端的, 就是每一个创建的对象都有各自一份属性和方法; 这里的弊端就是方法的重复。另外我们一旦写好了构造函数,不能在外面为构造函数添加属性和方法。为了解决这个问题  javascript为我们提供了prototype的一个属性。值得注意的是这个构造函数(Function 对象)的属性,不是对象实例的属性(注意这句话)。

         具体是这样的:

            function Person(name){

           this.name=name;}

           Person.prototype.sayName=function(){alert(this.name);}

        同时使用构造函数和原型的好处是:可以节省内存。这种模式基本上就创建对象的默认模式。

         5 其他方法;

        

          现在问题来了:原型是怎么回事? 

          先看一张图---------来自《javascript高级程序设计》 这是很有意思的图

         

        解释:

         在这里Person是一个构造函数, 我们看到有一个prototype属性,这个就是原型属性。他其实是一个指针, 指向一个对象,  这个对象叫原型对象  在这里是   Person.prototype  

         Person创建person1 person2 二个实例 ,图上我们可以看到实例中的 [[prototype]]属性,这是内部属性 (基本上不能外部访问) 这个对象是指向原型对象的(关键)。我们还可以看到

         原型对象的constructor属性是指向Person的。图中我们可以看到以上这些。 这样 Person.prototype.sayName=function(){alert(this.name);} 就是向原型对象中添加方法,我们通过person1.sayName();

      为什么可以访问方法?这就与[[prototype]]有关了,首先person1先找实例属性有没有叫sayName的方法,结果没有,那么就通过 [[prototype]] 找到原型对象,查找有没有sayName的方法,结果有那么就拿到了。

       因为一个构造函数只有一个原型对象与之对应,所有实例的[[prototype]]都是指向同一个原型对象的。所以原型里面的属性是公有属性,方法也是共有的。这个[[prototype]]在chrome ff中是 __proto__ 我们这样

       alert(person1.__proto__); 结果是[Object] ;  我们是不能通过实例直接为原型添加方法和属性的,只有通过构造函数才可以。值得注意的是Object.getPrototypeOf('object');在这里 Object.getPrototypeOf(person1)

      返回值是原型对象,这也是原型链继承的关键之处(这里先不讨论)。原型就是这样的。

         

      一个问题:

        说到原型,我们为一个构造函数添加方法时可以这样!

       Person.prototype={

        school:'一中',

      saySchoo:function(){

            alert(this.school); 

    }

      //code

    };

      这是对象字面量形式,我们会看到一些程序员这样写。那么有问题吗?

       有的,二个问题?

       (1)constructor属性问题。看上面我们知道这样写本质上重写了原型对象.constructor没有说明指向谁,那么就是window,不再是Person。我们可以这样

      Person.prototype={

        school:'一中',

      constructor:Person;

     saySchoo:function(){

       alert(this.school);  }

       //code};

    我们一般这样就可以了,不过和原来原型有一点个区别,就是constructor为可枚举(for in打印出该属性)。原来是不可以枚举的。 要和原来原型对象一样,那么应该这样。

    Person.prototype={

        school:'一中',

       saySchoo:function(){

        alert(this.school); 

    }

     //code

    };

     Object.defineProperty(Person.prototype,"constructor",{

    value:Person,

    enumerable:false; //不可以枚举;

      });

    这样就接近了。我们也可以不去设置,假定没有什么影响。

     

       (2)第二个问题就是

       function Person(){}

        var o=new Person();

    Person.prototype={

        school:'一中',

        saySchoo:function(){

           alert(this.school); 

            }//code

    };

    o.saySchool(); //无法访问,undefined

     原因是: o的[[prototype]]指向原来的 原型对象;现在重新写了,原型对象的位置变了,(函数中prototype不再指向旧的原型对象),但是o实例环视原来的,原来就没有这个方法,所有访问不到。

     ps:可能这些内容过于详细,不过了解还是好的,我们很多时候还是会使用这种模式重写原型对象的。就可能会有上面的二个bug;

        

      

     

        

  • 相关阅读:
    【转】centos(原生yum系通用)安装xfce便捷方法
    [转载]TortoiseGit安装与使用
    [转载]eclipse的远程调试功能配置
    oracle加密-des 简单举例.
    一个使用Servlet文件实现文件下载的实例
    (转载)JWebUnit做Web项目自动化测试
    得到类所在的jar包路径
    java实现https ssl请求url
    Java中用HttpsURLConnection访问Https链接
    [转载][Groovy] Groovy与Java的区别(一)
  • 原文地址:https://www.cnblogs.com/huang-1995/p/5731181.html
Copyright © 2011-2022 走看看