JS面向对象之封装

面向对象编程思想:

  以事物为重心, 考虑的是一件事情的完成有哪些事物参与了, 重点在于完善每种事物. 然后各种事物项目配合完成这件事儿.
面向对象的编程语言:

  Java, C#, Object-C, JavaScript...但是, JavaScript不是严格意义上面向对象的语言, 因为没有类的概念.
面向过程编程思想:

   以事件为重心, 考虑的是一件事情的完成需要怎样的步骤, 每个步骤都需要怎么处理.

JS是基于对象的若类型语言

在基于类的面向对象方式中,对象(object)依靠类(class)来产生。
在基于原型的面向对象方式中,对象(object)则是依靠构造函数(constructor)和原型(prototype)构造出来的。

 

JS封装

面向对象语言的第一个特性毫无疑问是封装,在 JS 中,封装的过程就是把一些属性和方法放到对象中“包裹”起来,那么我们要怎么去封装属性和方法

对象字面量 --> object对象 --> 工厂模式 --> 构造函数 --> 原型模式 --> 构造函数+原型模

 

对象字面量

   var dog = {
        // 属性 - 变量 
        color:'white',
        weight:'20kg',
        height:'0.6m',
        // 方法 - 函数 
        eat: function(){
            return '我要eat饭';
        },
        sleep: function(){
            console.log('我要睡觉');
        }
    }
    // 调用对象
    // 调属性
    console.log(dog.color);
    // 调方法
    var res = dog.eat();
    console.log(res);

 

Object方式创建

    var obj1 = new Object();
    // 属性
    obj1.color = 'white-2';
    obj1.height = '0.6m';
    // 方法
    obj1.eat = function(){
        console.log('我要eat饭-2');
    }
    // 调用对象
    // 调属性
    console.log(obj1.color);
    var str = 'color';
    console.log(obj1[str]); 
    // 注意:对象中的调用,.后面不能跟变量,变量需要使用 [] 
  • 优点:代码简单
  • 缺点: 创建多个对象会产生大量的代码,编写麻烦,且并没有实例与原型的概念。
  • 解决办法:工厂模式。

工厂模式

工厂模式是编程领域一种广为人知的设计模式,它抽象了创建具体对象的过程。JS 中创建一个函数,把创建新对象、添加对象属性、返回对象的过程放到这个函数中,用户只需调用函数来生成对象而无需关注对象创建细节,这叫工厂模式:

function createPerson(name='jack',age=18){ 
        var person = new Object();
        person.name = name;
        person.age = age;

        person.showName = function(){
            console.log('我的名字是:' + this.name);
        }
        person.showAge = function(){
            console.log('我的年龄是:' + this.age);
        }
        return person; // 对象
}
var per = createPerson('xiaoming',33); // person
  • 优点:工厂模式解决了对象字面量创建对象代码重复问题,创建相似对象可以使用同一API。
  • 缺点:因为是调用函创建对象,无法识别对象的类型。
  • 解决办法:构造函数

构造函数

function createPer(name='jack',age=18){
        // var obj = new Object();
        // 系统会自动创建
        // var this = new Object();
        this.name = name;
        this.age = age;

        this.showName = function(){
            console.log('我的名字是:' + this.name);
        }
        this.showAge = function(){
            console.log('我的年龄是:' + this.age);
        }
        // 省略:系统帮你自己返回
        // return obj
}
// 创建对象
var person = new createPer('zhangsan',19);

通过构造函数new一个实例经历了四步:

  1. 创建一个新对象;
  2. 将构造函数内的this绑定到新对象上;
  3. 为新对象添加属性和方法;
  4. 返回新对象(JS 引擎会默认添加 return this;

而通过构造函数创建的对象都有一个constructor属性,它是一个指向构造函数本身的指针,因此就可以检测对象的类型啦。:

alert(person.constructor === Person) //true
alert(person instanceof Person) // true

但是仍然存在问题

alert(person.showName == person2.showName) //false
  • 优点:解决了类似对象创建问题,且可以检测对象类型。
  • 缺点:构造函数方法要在每个实例上新建一次。
  • 解决办法:原型模式。

原型对象 + 构造对象

    function newPerson(name='jack',age=18){
        this.name = name;
        this.age = age;
    }
    // 原型方法
    // newPerson.prototype.
    newPerson.prototype.showName = function(){
        console.log('我的名字是:' + this.name);
    }
    newPerson.prototype.showAge = function(){
        console.log('我的年龄是:' + this.age);
    }
    // 创建对象
    var zhang = new newPerson('zhangsan',19);
    var peiqi = new newPerson('佩奇',2);
    zhang.showName();
    peiqi.showName();
    console.log(zhang.showName == peiqi.showName); // true
    // 构造函数
    console.log(newPerson.prototype.constructor);
  • 优点:与单纯使用构造函数不一样,原型对象中的方法不会在实例中重新创建一次,节约内存。
  • 缺点:使用空构造函数,实例 person1 和 person2 的 name都一样了,我们显然不希望所有实例属性方法都一样,它们还是要有自己独有的属性方法。并且如果原型中对象中有引用类型值,实例中获得的都是该值的引用,意味着一个实例修改了这个值,其他实例中的值都会相应改变。
  • 解决办法:构造函数+原型模式组合使用。

 

posted @ 2020-12-23 17:43  冉姑娘  阅读(542)  评论(0编辑  收藏  举报