zoukankan      html  css  js  c++  java
  • js的Prototype属性

    关于js中Prototype属性的解释和方法,看了某位大佬总结的一片博客,写的非常好啊,收益了,我这里转载备份一下,也加点一些小理解。后面有Prototype属性的新理解的话,会继续补充。不过关于原文中的类方法好像有点争议,有大佬科普下吗?

    原文:http://www.cnblogs.com/wdlhao/p/5743770.html

    1、prototype的定义

    javascript中的每个对象都有prototype属性,Javascript中对象的prototype属性的解释是:返回对象类型原型的引用。

    每一个构造函数都有一个属性叫做原型。这个属性非常有用:为一个特定类声明通用的变量或者函数。

    你不需要显式地声明一个prototype属性,因为在每一个构造函数中都有它的存在。你可以看看下面的例子:

    function Test(){}
    alert(Test.prototype); // 输出 "Object"

    1.1、 原型法设计模式

    原型法的主要思想是,现在有1个类A,我想要创建一个类B,这个类是以A为原型的,并且能进行扩展。我们称B的原型为A。

    1.2、javascript的方法可以分为三类:

    a 类方法

    b 对象方法

    c 原型方法

    复制代码
    function People(name)
    {
      this.name=name;
      //对象方法
      this.Introduce=function(){
        alert("My name is "+this.name);
      }
    }
    //类方法
    People.Run=function(){
      alert("I can run");
    }
    //原型方法
    People.prototype.IntroduceChinese=function(){
      alert("我的名字是"+this.name);
    }
     
    //测试
    var p1=new People("Windking");
    p1.Introduce();
    People.Run();
    p1.IntroduceChinese();
    复制代码

    1.3、给prototype添加属性

    就如你在上面所看到的,prototype是一个对象,因此,你能够给它添加属性。你添加给prototype的属性将会成为使用这个构造函数创建的对象的通用属性。

    例如,我下面有一个数据类型Fish,我想让所有的鱼都有这些属性:livesIn="water"和price=20;为了实现这个,我可以给构造函数Fish的prototype添加那些属性。

    复制代码
    function Fish(name, color){
       this.name=name;
       this.color=color;
    }
    Fish.prototype.livesIn="water";
    Fish.prototype.price=20;
    var fish1=new Fish("mackarel", "gray"); var fish2=new Fish("goldfish", "orange"); var fish3=new Fish("salmon", "white"); for (int i=1; i<=3; i++){ alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price); }
    复制代码

    输出应该是:

    "mackarel, gray, water, 20"
    "goldfish, orange, water, 20"
    "salmon, white water, 20"

    你看到所有的鱼都有属性livesIn和price,我们甚至都没有为每一条不同的鱼特别声明这些属性。这时因为当一个对象被创建时,这个构造函数 将会把它的属性prototype赋给新对象的内部属性__proto__。这个__proto__被这个对象用来查找它的属性

    你也可以通过prototype来给所有对象添加共用的函数。这有一个好处:你不需要每次在构造一个对象的时候创建并初始化这个函数。为了解释这一点,让我们重新来看Example DT9并使用prototype来重写它。

    1.4、用prototype给对象添加函数

    复制代码
    function Employee(name, salary){
        this.name=name;               
        this.salary=salary;
    }
    Employee.prototype.getSalary=function getSalaryFunction(){
        return this.salary;
    }
    Employee.prototype.addSalary=function addSalaryFunction(addition){
        this.salary=this.salary+addition;
    }
    var boss1=new Employee("Joan", 200000);
    var boss2=new Employee("Kim", 100000);
    var boss3=new Employee("Sam", 150000);
    复制代码

    输出的结果为:

    alert(boss1.getSalary());   // 输出 200000
    alert(boss2.getSalary());   // 输出 100000
    alert(boss3.getSalary());   // 输出 150000

    子类如何重写父类的属性或方法:

    复制代码
    function AClass(){
        this.Property = 1;
        this.Method = function(){
            alert(1);
        }
    }
    function AClass2(){
       this.Property2 = 2;
       this.Method2 = function(){
            alert(2);
       }
    }
    AClass2.prototype = new AClass();
    AClass2.prototype.Property = 3;
    AClass2.prototype.Method = function(){
       alert(4);
    }
    var obj = new AClass2();
    alert(obj.Property);
    obj.Method();
    复制代码

    输出结果为:

    //3
    //4

    可以在对象上增加属性或方法

    复制代码
    function Aclass(){
    this.Property = 1;
    this.Method = function(){
        alert(1);
    }
    }
    var obj = new Aclass();
    obj.Property2 = 2;
    obj.Method2 = function(){
        alert(2);
    }
    alert(obj.Property2);
    obj.Method2();
    复制代码

    输出结果为:

    //2
    //2
    在外部不能通过prototype改变自定义类型的属性或方法。该例子可以看到:调用的属性和方法仍是最初定义的结果。即当原型方法和对象方法在调用相同的属性和函数时,会执行对象方法里面的属性和函数。
    复制代码
    function Aclass(){
    this.Property = 1;
    this.Method = function(){
        alert(1);
    }
    }
    Aclass.prototype.Property = 2;
    Aclass.prototype.Method = function{
        alert(2);
    }
    var obj = new Aclass();
    alert(obj.Property);
    obj.Method();
    复制代码

    输出结果为:

    //1
    //1

    1.5、A.prototype = new B();

    理解prototype不应把它和继承混淆。A的prototype为B的一个实例,可以理解A将B中的方法和属性全部克隆了一遍。A能使用B的方法和属性。这里强调的是克隆而不是继承。可以出现这种情况:A的prototype是B的实例,同时B的prototype也是A的实例。

    先看一个实验的例子:

    复制代码
    function baseClass(){
      this.showMsg = function(){
         alert("baseClass::showMsg");   
      }
    }
    function extendClass(){}
    extendClass.prototype = new baseClass();
    var instance = new extendClass();
    instance.showMsg(); // 显示baseClass::showMsg
    复制代码

    我们首先定义了baseClass类,然后我们要定义extentClass,但是我们打算以baseClass的一个实例为原型,来克隆的extendClass也同时包含showMsg这个对象方法。

    extendClass.prototype = new baseClass()就可以阅读为:extendClass是以baseClass的一个实例为原型克隆创建的。

    那么就会有一个问题,如果extendClass中本身包含有一个与baseClass的方法同名的方法会怎么样?

    下面是扩展实验2:

    复制代码
    function baseClass(){
        this.showMsg = function(){
            alert("baseClass::showMsg");   
        }
    }
    
    function extendClass(){
        this.showMsg =function (){
            alert("extendClass::showMsg");
        }
    }
    extendClass.prototype = new baseClass();
    var instance = new extendClass();
    
    instance.showMsg();//显示extendClass::showMsg
    复制代码

    实验证明:函数运行时会先去本体的函数中去找,如果找到则运行,找不到则去prototype中寻找函数。或者可以理解为prototype不会克隆同名函数

    那么又会有一个新的问题:如果我想使用extendClass的一个实例instance调用baseClass的对象方法showMsg怎么办?

    答案是可以使用call:

    extendClass.prototype = new baseClass();
    var instance = new extendClass();
    
    var baseinstance = new baseClass();
    baseinstance.showMsg.call(instance);//显示baseClass::showMsg

    这里的baseinstance.showMsg.call(instance);阅读为“将instance当做baseinstance来调用,调用它的对象方法showMsg”

    好了,这里可能有人会问,为什么不用baseClass.showMsg.call(instance);

    这就是对象方法和类方法的区别,我们想调用的是baseClass的对象方法

    1.6、对象方法与通过new创建对象的重要区别

    这个区别就是function定义的方法(对象方法)有一个prototype属性,使用new生成的对象就没有这个prototype属性。也就是prototype属性是对象方法或者构造方法的专有属性。 prototype属性又指向了一个prototype对象,注意prototype属性与prototype对象是两个不同的东西,要注意区别。在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身。如下所示:

       (这个图没看懂啊=-=,又涉及到了constructor)

    复制代码
    function Person(name)  
    {  
       this.name=name;  
       this.showMe=function()  
            {  
               alert(this.name);  
            }  
    };    
    var one=new Person('js');    
    alert(one.prototype)//undefined  
    alert(typeof Person.prototype);//object  
    alert(Person.prototype.constructor);//function Person(name) {...};  
    复制代码

    最后,下面这个代码如果理解清晰,那么这篇文章说的就已经理解了:

     1 <script type="text/javascript">
     2 
     3 function baseClass()
     4 {
     5     this.showMsg = function()
     6     {
     7         alert("baseClass::showMsg");   
     8     }
     9    
    10     this.baseShowMsg = function()
    11     {
    12         alert("baseClass::baseShowMsg");
    13     }
    14 }
    15 baseClass.showMsg = function()
    16 {
    17     alert("baseClass::showMsg static");
    18 }
    19 
    20 function extendClass()
    21 {
    22     this.showMsg =function ()
    23     {
    24         alert("extendClass::showMsg");
    25     }
    26 }
    27 extendClass.showMsg = function()
    28 {
    29     alert("extendClass::showMsg static")
    30 }
    31 
    32 extendClass.prototype = new baseClass();
    33 var instance = new extendClass();
    34 
    35 instance.showMsg(); //显示extendClass::showMsg
    36 instance.baseShowMsg(); //显示baseClass::baseShowMsg
    37 instance.showMsg(); //显示extendClass::showMsg
    38 
    39 baseClass.showMsg.call(instance);//显示baseClass::showMsg static
    40 
    41 var baseinstance = new baseClass();
    42 baseinstance.showMsg.call(instance);//显示baseClass::showMsg
    43 
    44 </script>

     注意第十五行的是类方法,作者这里打上static的调试信息,那有点和Java的静态有点像了啊,类共用,一个模版,js上面代码这里专门用来区别第五行的对象方法,两个输出的信息不一样。第三十九行和四十二行显示了结果。在上面的extendClass的一个实例instance调用baseClass的对象方法showMsg 也有提到。

  • 相关阅读:
    字符串替换
    字符串查找
    字符串比较
    字节与字符串相互转换
    1365. How Many Numbers Are Smaller Than the Current Number
    1486. XOR Operation in an Array
    1431. Kids With the Greatest Number of Candies
    1470. Shuffle the Array
    1480. Running Sum of 1d Array
    【STM32H7教程】第56章 STM32H7的DMA2D应用之刷色块,位图和Alpha混合
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/7620415.html
Copyright © 2011-2022 走看看