javascript学习五---OOP

面向对象:JavaScript的所有数据都可以看成对象
JavaScript的面向对象编程和大多数其他语言如Java、C#的面向对象编程都不太一样。如果你熟悉Java或C#,很好,你一定明白面向对象的两个基本概念:
   面向对象的两个基本概念:
       1、类:类是对象的类型模板,例如,定义Student类来表示学生,类本身是一种类型,Student表示学生类型,但不表示任何具体的某个学生;
       2、实例:实例是根据类创建的对象,例如,根据Student类可以创建出xiaoming、xiaohong、xiaojun等多个实例,每个实例表示一个具体的学生,他们全都属于Student类型。
       所以,类和实例是大多数面向对象编程语言的基本概念。

   JavaScript不区分类和实例的概念,而是通过原型(prototype)来实现面向对象编程。
   JavaScript的原型链和Java的Class区别就在,它没有“Class”的概念,所有对象都是实例,所谓继承关系不过是把一个对象的原型指向另一个对象而已。

   JS的prototype和__proto__
        一、prototype和__proto__的概念
            prototype是函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象。它是显示修改对象的原型的属性。
            __proto__是一个对象拥有的内置属性(请注意:prototype是函数的内置属性,__proto__是对象的内置属性),是JS内部使用寻找原型链的属性
            用chrome和FF都可以访问到对象的__proto__属性,IE不可以。

        二、new 的过程
            var Person = function(){};
            var p = new Person();
            new的过程拆分成以下三步:
            (1) var p={}; 也就是说,初始化一个对象p
            (2) p.__proto__ = Person.prototype;
            (3) Person.call(p); 也就是说构造p,也可以称之为初始化p
            关键在于第二步,我们来证明一下:
            var Person = function(){};
            var p = new Person();
            alert(p.__proto__ === Person.prototype);

       三、示例
            var Person = function(){};
            Person.prototype.sayName = function() {
                alert("My Name is Jacky");
            };
            Person.prototype.age = 27;
            var p = new Person();
            p.sayName();

        p是一个引用指向Person的对象。我们在Person的原型上定义了一个sayName方法和age属性,当我们执行p.age时,会先在this的内部查找(也就是构造函数内部),如果没有找到然后再沿着原型链向上追溯。
        这里的向上追溯是怎么向上的呢?这里就要使用__proto__属性来链接到原型(也就是Person.prototype)进行查找。最终在原型上找到了age属性



      为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。
      所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。
      案例:
        function Cat(name,color){
            this.name=name;
            this.color=color;

          }
          我们现在就可以生成实例对象了。
          var cat1 = new Cat("大毛","黄色");
          var cat2 = new Cat("二毛","黑色");
          alert(cat1.name); // 大毛
          alert(cat1.color); // 黄色

            这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。
           alert(cat1.constructor == Cat); //true
            alert(cat2.constructor == Cat); //true
      Javascript还提供了一个instanceof运算符,验证原型对象与实例对象之间的关系。
          alert(cat1 instanceof Cat); //true
          alert(cat2 instanceof Cat); //true

      五、 Prototype模式
            Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
            这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。
            这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

          function Cat(name,color){
            this.name = name;
            this.color = color;
          }
          Cat.prototype.type = "猫科动物";
          Cat.prototype.eat = function(){alert("吃老鼠")};

      六、 Prototype模式的验证方法
          6.1 isPrototypeOf()
            这个方法用来判断,某个proptotype对象和某个实例之间的关系。
              alert(Cat.prototype.isPrototypeOf(cat1)); //true
              alert(Cat.prototype.isPrototypeOf(cat2)); //true

         6.2 hasOwnProperty()
            每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。
              alert(cat1.hasOwnProperty("name")); // true
              alert(cat1.hasOwnProperty("type")); // false

         6.3 in运算符

            in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。
              alert("name" in cat1); // true
              alert("type" in cat1); // true
            in运算符还可以用来遍历某个对象的所有属性。
              for(var prop in cat1) { alert("cat1["+prop+"]="+cat1[prop]); }


比如,现在有一个"动物"对象的构造函数。
  function Animal(){
    this.species = "动物";
  }

还有一个"猫"对象的构造函数。

  function Cat(name,color){
    this.name = name;
    this.color = color;
  }

怎样才能使"猫"继承"动物"呢?
一、 构造函数绑定
    第一种方法也是最简单的方法,使用call或apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:
   function Cat(name,color){
        Animal.apply(this, arguments);
        this.name = name;
        this.color = color;
  }
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

二、 prototype模式

第二种方法更常见,使用prototype属性。
如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。

  Cat.prototype = new Animal();
  Cat.prototype.constructor = Cat;
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

任何一个prototype对象都有一个constructor属性,指向它的构造函数。

案例:
class Student {
    constructor(name) {
        this.name = name;
    }
    hello() {
        console.log('Hello, ' + this.name + '!');
    }
};
var xiaoming = new Student('小明');
xiaoming.hello();

结果:Hello, 小明!

class PrimaryStudent extends Student {
    constructor(name, grade) {
        super(name); // 记得用super调用父类的构造方法!
        this.grade = grade;
    }
    myGrade() {
        alert('I am at grade ' + this.grade);
    }
};
var teddy = new PrimaryStudent('teddy','no.1');
teddy.myGrade();

结果:'I am at grade no.1'

 

posted @ 2020-12-28 22:29  何双新  阅读(70)  评论(0编辑  收藏  举报