zoukankan      html  css  js  c++  java
  • JavaScript的面向对象编程(OOP)(二)——原型

    关于JavaScript的原型模式,下面的是学习后的个人理解,若是有偏差,还请指出,谢谢

    JavaScript原型模式

    1.什么是原型?

    原型是一个对象,其他的对象可以通过它实现属性的继承,所有的对象在默认情况下都只有一个原型,而且原型本身也是一个对象。所以一个类的真正原型是被类内部的[prototype]属性所指出的。如下,我们先看一个空对象和它的原型

    //定义一个空对象
    function Person(){
    }
    Person.prototype.name = "username";
    Person.prototype.getName = function(){
          alert(this.name);//此处的this表示调用本方法的一个具体的实例化对象           
    }

    这样,我们给一个Person的空的对象增加了一个原型属性name,和一个原型方法getName();通过 new Person().showName(); 能直接调用它的原型方法,并将原型属性name弹出。我们用对象集的方法表示原型

    function Person(){
    }
    Person.prototype = {
           name : "plum",
           showName : function(){
                  alert(this.name);
           }      
    }

    这样便能清晰的表示出原型本身也是一个对象,并且被Person对象(此时这是一个类)所持有的属性prototype所指出。

    2.那什么是对象呢?

    在JavaScript中,一个对象就是任何的无序的键值对的集合,也就是除了五种的基本数据类型(number,string,boolean,null,undefined)其他的都是对象。

    上述的例子中我们用functions定义的对象,那如果我们用var 或者new 直接创建的json对象和用构造函数实例化的对象又是怎么改变原型的引用的呢?

    new Person().getName();//弹出username
    var a = new Person();
    a.__proto__.name = "v";//使用__proto__改变原型
    a.getName();//弹出v
    new Person().getName();//弹出v

    通过上面一开始弹出的最开始的username,我们使用__proto__属性更改了原型模式之后再运行弹出v,由此我们可以知道使用new关键字的生成出来的对象都持有一个__proto__属性,这个属性保存了创建它的构造函数的prototype的原型的引用。

    使用var直接创建的对象的原型引用

    var cat = {}; //cat空类
    Object.getPrototypeOf(cat).name = "plum";
    cat.__proto__.master = "bote";
    cat.age = 2;//隐式调用,cat.__proto__.age = 2,即隐藏了__proto__的调用
    cat["sex"] = "man";
    alert(cat.name+" "+cat.age+" "+cat["sex"]+" "+cat.master);//弹出plum 2 man bote

    使用var直接创建的空类无法通过 cat.prototype.name = "plum" 方式来指向原型,只能通过Object.getPrototypeOf()或__proto__这两种方式显示调用 prototype而一般我们都是直接使用 cat.age或cat["age"]这两种隐式调用。

    3.关于原型的继承

    下面我们通过原型模式实现简单的继承

    function per(){
          this.getName = function(str){
               alert(str);
           };
    }
    per.prototype.getAge = function(age){
                alert(age);
    }
    var a = {};//空对象,实现继承上面的类
    a.__proto__= per.prototype;
    a.getAge(2);

    这种种方式实现的继承是简单继承,我们如果调用 a.getName("sad"); 此时a.getName is not function,并不能继承per内部的getName方法,所以这种继承是简单的继承,只有当被继承的类是空对象的时候,才能完全继承,只能继承Prototype的属性和方法。

    下面我们用简单的方式实现继承

    var b = {}; //空对象,是它完全继承上面的per(){}
    b.__proto__ = new per();
    //构造函数(constructor),将b的构造函数,变回他自己本身的构造函数
    b.__proto__.constructor = b;
    b.getAge(1);
    b.getName("huahua");

    这样种方式,我们便将per类完全继承过来了。

    下面我们再来看一个完整的继承

    //创建一个人员类
    function Person(name){
             this.name = name;
    }
    //创建教师类
     function  Teacher(name,books){
              //call方法可以将一个函数的对象上下文从初始化变成由this来决定
              //调用Person的构造函数,因为Person没有new,所以它是个空对象
               Person.call(this,name);
               this.books = books;
    }
    //使老师继承人员类
    Teacher.prototype = new Person();
    Teacher.prototype.constructor = Teacher;
    Teacher.prototype.getBooks = function(){
                return this.name + " " + this.books;
    }
    var jim = new Teacher("Tom","JavaScript");
    alert(jim.getBooks());

    Teacher继承了Person,在原型中添加了getBooks的方法。

    我们也可以写出Extend的方法,实现所有的继承

    function extend(subClass,superClass){
    //1.子类的原型类属性等于父类的原型属性
    //初始化一个中间空对象,为了转换子父类关系
           var F = function(){};
           F.prototype = subClass.prototype;
    //2.让子类继承F
            subClass.prototype = new F();
            subClass.prototype.constructor = subClass;
    //3.为子类增加superClass的属性
             subClass.superClass = superClass.prototype;
    //4.如果原型类是超类(object),也要把构造函数的级别降下来
             if(subClass.prototype.constructor == Object.prototype.constructor){
                        superClass.prototype.constructor = subClass;
             }
    }

    这样我们通过这和extend方法能直接实现继承,下面我们使用这个方法来测试效果

    function Author(name,books){
           Author.superClass.constructor.call(this,name);
           this.books = books;
           this.getBook = function(){
                  return this.name + " " + this.books;
           }
    }
    extend(Author,Person);
    var peter = new Author("Peter","javascript");
    alert(peter.getBook());

    这样,以后便能用extend的方式直接继承,要注意,JavaScript中无法实现多继承。

    关于继承的问题尽量都在代码和代码描述里,要在实例中理解,不能只看概念,不然只能是云里雾里,有疑问的地方多敲一下测试代码,就能理解。

  • 相关阅读:
    学习进度条54
    学习进度条53
    学习进度条52
    学习进度条51
    学习进度条50
    学习进度条49
    学习进度条48
    学习进度条47
    学习进度条45
    线程池中的阻塞队列选择
  • 原文地址:https://www.cnblogs.com/LVPlum/p/5525863.html
Copyright © 2011-2022 走看看