2-面向对象3大特性 创建对象的4种方式 构造函数注意点 构造函数的原型对象(使用方法/注意事项) 实例/实例化 实例/原型成员

面向对象的三大特性

  • 封装: 在JS中使用对象封装一些变量和函数
    • 好处: 信息隐蔽, 方便扩展维护, 提高代码的复用性
  • 继承: 一个类(对象)获取另一个类(对象)的属性和方法的一种形式
    • 面向对象语言定义: 是否有类的概念(c++ Java)
    • JS没有类的概念, JS从这个角度说不是面向对象语言. 但面向对象具有继承特性, 可以说JS支持面向对象语言
  • 多态: 同一操作, 作用于不同对象, 会产生不同行为(解释)
    • 实现: JS天生就具有多态的特性(弱类型语言)

创建对象的方式

  1. 字面量的方式

     var student = {
         name: 'zs',
         age: 16,
         class: '一分钟精通JS'
     }
     //一个班级有N个学生, 通过字面量形式, 需要创建N个学生对象
     //问题: 创建多个同类型的对象时, 大量代码冗余(重复代码)
     //价值: 只需要创建简单的几个对象
    
  2. 内置的构造函数

    • 系统内置的构造函数: Object | Array | Math | Date | Function | String | Number | Boolean

        var stu = new Object();
        stu.name= 'zs';
        stu.age= 16;
        stu.class=  '一分钟精通JS';
        //跟字面量的方式差不多, 问题也是一样-->创建对象的相同部分进行函数封装(简单工厂)
      
  3. 简单的工厂方式: 类似函数封装, 相同的不变, 不同的作为参数传进来

     function person(){
         var stu = new Object();
         stu.name= 'zs';
         stu.age= 16;
         stu.class=  '一分钟精通JS';
         //返回该对象
         return stu;
     }
     var stu1 = person();
     var stu2 = person();    
     //问题: 两个学生信息都一样
    
     //优化如下: 不同的信息当做参数传进来                
     function person(name, age, classes){
         var stu = new Object();
         stu.name= name;
         stu.age= age;
         stu.class=  classes;
         return stu;
     }               
     function dog(name, age, classes){
         var dog = new Object();
         dog.name= name;
         dog.age= age;
         dog.class= classes;
         return dog;
     }
     var stu3 =  person('zs', 16, '一分钟精通JS' );   
     var dog = dog('wangCai', 5 , '骑单车');
     console.log(stu3 == dog);    //false
     //问题: 创建不同类型的对象时, 无法分辨其类型       
    
  4. 自定义构造函数-参照上一章构造函数创建对象

    • 定义

      • 自己定义的构造函数(首字母大写)-通过this设置属性/方法-使用new调用构造函数创建对象
    • 执行过程

      1. 通过new关键字调用构造函数,构造函数内部默认创建一个新对象
      2. 将这个新对象赋值给this
      3. 通过this设置属性和方法
      4. 默认返回新创建对象
    • 返回值

      • 如果没有显示return, 默认返回构造函数内部新创建的对象
      • 若写了返回值, 要看具体情况
        • 如果返回值类型的数据, 就直接忽略, 返回内部新创建的对象
        • 若返回引用类型的数据, 直接返回该数据(会覆盖内部新创建的对象)
    • 自定义构造函数(区别于简单的工厂函数)

      1. 函数名首字母大写
      2. 自定义构造函数内部会默认创建一个对象-默认将这个对象赋值给this
      3. 默认会返回新创建的对象
      4. 创建不同类型的对象时, 可以分辨其类型

构造函数注意事项

  1. 函数传值: 函数当做参数传进构造函数
  2. 判断对象的类型
    • 对象 instanceof 构造函数: 判断指定对象是否由某个构造函数创建出来
  3. 获取对象类型: 构造器属性obj.constructor
  4. 构造函数调用-区别于函数调用
    • new关键字: 默认创建/返回对象

    • 构造函数: 对这个对象进行一些初始化的操作(将创建对象赋值给this, 通过this绑定属性/方法)

         function Person(name) {
              // this = obj;
      
              console.log(this);
              this.name = name;
              // return obj;
         }
        var p1 = new Person('zs');
      
        // 构造函数也是一个函数
        var p2 = Person('ls'); // 可以这样写,但是不建议这样做
        console.log(p2); // undefined, 直接调用构造函数,this指向window
      
       //分析打印结果
       <script>
            function fn(){
                var t = 1;
                this.x = 3;
                document.write(t);
                document.write(this.x);
            }
            var obj = new fn();
            document.write(obj.x);
            document.write(fn());
        </script>
      

构造函数的原型对象

  1. 原型对象定义

    • 在构造函数创建出来时, 系统默认会创建一个对象与这个构造函数相关联, 这个对象称为该构造函数的原型对象


      构造函数的原型对象
  2. 作用

    • 使用构造函数创建出来的对象, 默认就可以使用该构造函数原型对象的属性和方法
  3. 访问原型对象: 构造函数.prototype

  4. 设置原型对象: 构造函数.prototype.name = 'name1';

    • 原型对象本质也是一个对象, 可以利用对象的动态特性设置原型对象
  5. 约定

    • 该对象构造函数的原型对象
    • 构造函数的原型对象(原型) | 对象的原型对象(原型)

实例与实例化

  • 实例: 通过构造函数创建出来的对象.
    • 一般说: XX是构造函数的实例
    • 实例成员: 实例属性+实例方法
  • 实例化: 通过构造函数创建对象的过程
  • 注意点
    • 实例对象可以访问实例成员和原型成员, 但是不能够访问静态成员
    • 构造函数在访问静态方法时, 内部的this指向的是构造函数自己, 不能访问到实例对象的成员
    function Person() {
        this.name = "张三";   //实例属性
        var age = 18;       //私有变量
        this.showName = function () {       //实例方法
            console.log(this.name);
        }
        this.showAge = function () {    //特权方法
            console.log(age);   
        }
    }   
    Person.prototype.show = function () {   //原型方法
        console.log(this.name);
    }   
    Person.des = function () {  //静态方法
        console.log(this.name);
    }   
    var p1 = new Person();

    p1.showName();  //张三
    p1.showAge();   //18
    p1.show();      //张三
    //p1.des();       //undefined ? 报错(Y)
    Person.des();     //undefined ? 报错 ? 张三 ?Person(Y)

原型的使用方法

  • 利用对象的动态特性设置原型对象
    • 提供一个构造函数
    • 设置原型对象的成员(原型属性+原型方法)
      • 添加成员: 构造函数.prototype.name = "name1";
      • 修改成员: 构造函数.prototype.name = "name2";
      • 删除成员: delete 构造函数.prototype.name;
  • 替换原型对象: 自己定义的对象赋值给原型对象
    1. 替换原型对象之前创建的对象和替换之后创建的对象,他们的原型对象不是同一个对象
    * 注意点: 获取替换原型对象的属性与替换之前原型对象的属性值不相等
    * 建议: 最好在替换原型对象之后, 再创建对象
    
    1. 修正构造器属性

使用原型对象的注意事项

  • 访问原型对象的属性-方式
    1. 对象.属性(就近原则)
      • 首先查找自身是否有该属性, 若有就直接使用
      • 若没有就查找该对象原型对象的属性, 若有就直接使用
      • 再没有就返回undefined或报错
    2. 构造函数.prototype.属性
  • 设置原型对象
    • 通过对象.属性设置属性
      • 如果有这个属性就是修改, 没有这个属性就是添加属性, 不会修改原型对象的属性
    • 设置原型对象的属性
      • 通过构造函数.prototype.属性或者替换原型
      • 如果原型属性是引用类型的数据, 可以通过对象.属性.属性的方式修改

构造器属性相关

  • constructor属性: 指向与之对应的构造函数
  • 对象.constructor: 访问的是原型对象的constructor属性

__proto__属性

  • 定义
    • 构造函数创建出来的对象, 默认就有一个__proto__属性, 该属性指向该对象对应的构造函数的原型对象
  • 访问原型对象-方式
    1. 构造函数.prototype
    2. 对象.__proto__
      • 注意点: 在正式开发中, 不建议使用. 该属性不是ES标准, 是部分浏览器厂商方便调试程序


        __proto__和constructor结构关系图

hasOwnProperty()

  • 语法: 对象.hasOwnProperty("属性名")
  • 定义: 判断对象中是否存在指定的属性(实例属性)/ES5 中判断对象的自有属性(hasOwnProperty)
  • in区别: in判断对象中是否存在指定的属性(不区分实例属性/原型属性)

isPrototypeOf()

  • 语法: 构造函数.protoType.isPrototypeOf(对象)
  • 定义: 判断一个对象是否是指定对象的原型对象(判断原型对象是否在整条原型链上)
  • instanceof区别: instanceof判断一个对象是否是指定构造函数的实例对象
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容