zoukankan      html  css  js  c++  java
  • JavaScript 构造函数相关

    JavaScript中的对象概念和其他语言的对象概念有些不一样,所以学习起来稍微有点特殊。

    • 在JavaScript中,构造函数的使用一般如下:

      /*
        function MyConstructor(){
          // 函数实体写在这里
          // 根据需要在this上创建属性,然后赋值给它们,比如:
          this.a = 123;
          // 等等...
       
          // 如果函数具有返回对象的return语句,
          // 则该对象将是 new 表达式的结果。 
          // 否则,表达式的结果是当前绑定到 this 的对象。
          //(即通常看到的常见情况,其实就是在调用函数)。
        }
       */
      
      function C(){
        this.a = 37;
      }
      
      var o = new C();
      console.log(o.a); //会输出 37
      
      
      function C2(){
        this.a = 37;
        return {a:38};
      }
      
      o = new C2();
      console.log(o.a); //会输出 38
      
    • 所谓的“构造函数”,其实本质上还是一个普通的函数,但是由于在内部使用了this变量,如果对构造函数使用new运算符,就能够生成一个实例化的对象出来,并且在构造函数里面所使用到的this变量或方法,都会绑定到这个实例对象上面来。

      如果此时写一个人的构造函数,可以简单这么写:

      function Person(name, age, sex){
      	this.name = name;
          this.age = age;
          this.sex = sex;
      }
      

      实例化一个人的对象出来的话,可以这么来使用:

      var zhangsan = new Person("zhangsan", 18, "男");
      var lisi = new Person("lisi", 19, "男");
      
      console.log(typeof zhangsan); //object
      console.log(zhangsan); //Person { name: 'zhangsan', color: 18, sex: '男' }
      console.log(typeof lisi); //object
      console.log(lisi); //Person { name: 'lisi', color: 19, sex: '男' }
      

      经过上面的操作,就会构造两个Person的对象zhangsanlisi出来,这两个对象都自动会含有一个constructor属性,指向它们的构造函数;也可以通过instanceof运算符来验证实例对象和原型对象的关系:

      console.log(zhangsan.constructor === Person);//True
      console.log(lisi.constructor === Person);//True
      
      console.log(zhangsan instanceof Person);//True
      console.log(lisi instanceof Person);//True
      
    • 构造函数的prototype属性,每个构造函数都拥有一个protorype属性,能够指向另外一个对象,这个对象的所有属性和方法,都会被构造函数的实例所继承,这样就可以把对象的一些通用不变的属性和方法直接定义在prototype对象上:

      function Person(name, age, sex){
      	this.name = name;
          this.age = age;
          this.sex = sex;
      }
      
      Person.prototype.species = "人类";
      Person.prototype.eat = function () {
          console.log("吃东西");
      }
      
      var zhangsan = new Person("zhangsan", 18, "男");
      
      console.log(zhangsan.species); //人类
      zhangsan.eat(); //吃东西
      
      

      这个时候所有实例化对象的type属性和eat()方法,其实都是指向prototype对象。

    • 可以使用isPrototypeOf()方法来判断某个proptotype对象和某个实例之间的关系:

      console.log(Person.prototype.isPrototypeOf(zhangsan)); //True
      
    • 可以使用hasOwnProperty()方法来判断对象的某个属性是本身属性还是proptotype对象的属性:

      console.log(zhangsan.hasOwnProperty("sex")); //True
      console.log(zhangsan.hasOwnProperty("species")); //False
      
    • JavaScript中的in运算符可以用来判断实例化对象是否含有某个属性[无论是不是本身的属性],也可以用来遍历某个对象的所有属性。

    构造函数的继承的五种方法

    此时这里有两个构造函数,PersonDeveloper,如下:

    function Person(){
      this.species = "人类";
    }
    
    function Developer(name, age, sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    
    • 使用call()或者apply()的方法,将父对象的构造函数绑定在子对象上面,实现如下:

      function Developer(name, age, sex){
          
          //使用apply方法
      	Person.apply(this, arguments);
          //或者使用call方法
          //Person.call(this, name, age, sex);
          
          this.name = name;
          this.age = age;
          this.sex = sex;
      }
      
      var developer_1 = new Developer("zhangsan", 20, "男");
      console.log(developer_1);
      //Developer { species: '人类', name: 'zhangsan', age: 20, sex: '男' }
      
    • 使用prototype属性:

      function Person(){
          this.species = "人类";
      }
      
      function Developer(name, age, sex){
          this.name = name;
          this.age = age;
          this.sex = sex;
      }
      
      
      Developer.prototype = new Person();
      Developer.prototype.constructor = Developer;
      
      var developer_1 = new Developer("zhangsan", 20, "男");
      
      console.log(developer_1);
      // Developer { name: 'zhangsan', age: 20, sex: '男' }
      console.log(developer_1.species); 
      // 人类
      
      
      

      Developer.prototype = new Person();就相当于给构造函数Developerprototype对象重新赋了一个新的值;又由于任何一个prototype对象都有一个constructor属性,指向它的构造函数的。而且每个实例的constructor属性,默认调用prototype对象的constructor属性。

      因此此时Developerprototype对象的constructor属性就是指向Person的,这个时候加上Developer.prototype.constructor = Developer;,会让Developerprototype对象的constructor属性就是指向Developer

    • 直接继承prototype

      这种方式是将不变的父类的属性直接写入到它的prototype上面,此时直接将父类的protptype属性赋值给子类的prototype,然后再更改子类的prototypeconstructor属性指向即可,这种方式的优点是效率较高[不用执行和建立Person的实例了],缺点是两个构造函数的prototype属性是指向同一个对象的,那么任何修改都会映射到两个上面:

      function Person() {
      
      }
      Person.prototype.species = "人类";
      
      function Developer(name, age, sex){
          this.name = name;
          this.age = age;
          this.sex = sex;
      }
      
      
      Developer.prototype = Person.prototype;
      Developer.prototype.constructor = Developer;
      
      var developer_1 = new Developer("zhangsan", 20, "男");
      
      console.log(developer_1);
      // Developer { name: 'zhangsan', age: 20, sex: '男' }
      console.log(developer_1.species);
      // 人类
      
      
      // 缺点就是两个prototype会指向同一个
      console.log(Developer.prototype.constructor);
      // [Function: Developer]
      console.log(Person.prototype.constructor);
      // [Function: Developer]
      
      
    • 在直接继承prototype的基础上,可以再利用一个空对象做中介

      因为直接继承prototype这种方式仍有一些缺点,所以此时可以这么做:

      function Person() {
      
      }
      Person.prototype.species = "人类";
      
      function Developer(name, age, sex){
          this.name = name;
          this.age = age;
          this.sex = sex;
      }
      
      var F = function(){};
      F.prototype = Person.prototype;
      Developer.prototype = new F();
      Developer.prototype.constructor = Developer;
      

      这样对Developerprototype对象的修改,就不会影响到Person,而是修改到了F上面,此时还可以继续改进,将上面的代码封装到一个函数里面,更加方便使用:

      function packaging(Child, Parent) {
          var F = function () {
          };
          F.prototype = Parent.prototype;
          Child.prototype = new F();
          Child.prototype.constructor = Child;
          //uber属性:指向父类原型。
          Child.uber = Parent.prototype;
      }
      
      packaging(Developer, Person)
      
      var developer_1 = new Developer("zhangsan", 20, "男")
      console.log(developer_1) // Developer { name: 'zhangsan', age: 20, sex: '男' }
      
    • 拷贝继承

      如果纯粹采用"拷贝"方法实现继承。简单说,如果把父对象的所有属性和方法,拷贝进子对象,也能够实现继承,具体如下:

      function Person() {
      
      }
      Person.prototype.species = "人类";
      
      function Developer(name, age, sex){
          this.name = name;
          this.age = age;
          this.sex = sex;
      }
      
      function copy_inherit(Child, Parent) {
          var parent = Parent.prototype;
          var child = Child.prototype;
          for (var attribute in parent){
              child[attribute] = parent[attribute];
          }
          child.uber = parent;
      }
      
      copy_inherit(Developer, Person)
      
      var developer_1 = new Developer("zhangsan", 20, "男")
      console.log(developer_1) //Developer { name: 'zhangsan', age: 20, sex: '男' }
      console.log(developer_1.species)// 人类
      

    参考 Javascript面向对象编程(二):构造函数的继承

  • 相关阅读:
    Jenkins-在windows上配置自动化部署(Jenkins+Gitblit)
    GIT-Linux(CentOS7)系统部署GitLab服务器
    VMware 安装Linux系统 CentOS
    GIT-windows系统下Gitblit的使用方式
    SQL 显示所有表所占存储空间
    通过JavaScript更新UpdatePanel备忘
    Entity Framework调用表值函数实现全文检索?
    转载:javascript 拖拽排序,简洁示例备忘
    c++ 读写注册表
    MSSQL中建立分区表(转载备忘)
  • 原文地址:https://www.cnblogs.com/grubber/p/13094044.html
Copyright © 2011-2022 走看看