面向对象编程-封装

118 阅读5分钟

面向对象编程

概念

面向对象编程就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法)。这个对象我们称之为类。

特点

  • 封装:面向对象编程思想其中有一个特点就是封装,就是说把你需要的功能放在一个对象里。
  • 继承:javascript对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

包装明星 - 封装

创建一个类

在Javascript中创建一个类很容易,首先声明一个函数保存在个变量里。按编程习惯一般将这个代表类的变量名首字母大写。然后在这个函数(类)的内部通过对this(函数内部自带的一个变量,用于指向当前这个对象)变量添加属性或者方法来实现对类添加属性或者方法。

  1. 通过this添加属性和方法
var Book = function(id, bookname, price) {
    this.id = id;
    this.bookname = bookname;
    this.price = price;
}

  1. 通过类的原型(类也是个对象,所以也有原型prototype)上添加属性和方法
    Book.prototype.display = function() {
        // 展示这本书
    }
    或者
    Book.prototype = {
        display: function() {}
    }

这样我们将所需要的方法和属性都封装在我们抽象的Book类里面了,当使用功能方法时,我们不能直接使用这个Book类,需要用new关键字来实例化(创建)新的对象。使用实例化对象的属性或方法时,可以通过点语法访问。

    var book = new Book(1, 'Javascript设计模式', 10);
    console.log(book.bookname) // Javascript设计模式

通过this添加的属性和方法与通过prototype中添加的属性和方法的区别

通过this添加的属性、方法是在当前类创建的对象上添加的,然后JavaScript是一种基于原型prototype的语言,所以每创建一个对象时(当然在JavaScript中函数也是一种对象),他都有一个原型prototype用于指向其继承的属性、方法。这样通过prototype继承的方法并不是对象自身的,所以在使用这些方法时,需要通过prototype一级一级查找来得到。

这样你会发现通过this定义的属性或者方法是该对象自身拥有的,所以我们每次通过类创建一个新对象时,this指向的属性和方法都会得到相应的创建,而通过prototype继承的属性和方法是每个对象通过prototype访问到,所以我们每次通过类创建一个新对象时prototype上的这些属性和方法不会再次创建。

constructor概念

constructor是一个属性,当创建一个函数或者对象时都会为其创建一个原型对象prototype,在prototype对象中又会像函数中创建this一样创建一个constructor属性,那么constructor属性指向的就是拥有整个对象的函数或者对象。

prototype.png 原型对象prototype

属性和方法封装

  1. 私有方法、私有属性

由于JavaScript的函数级作用域,声明在函数内部的变量以及方法在外界是访问不到的,通过此特性即可创建类的私有方法以及私有属性。

  1. 公有方法、公有属性

通过this创建的属性可以看做是对象共有方法和对象共有属性

  1. 特权方法 || 构造器

通过this创建的方法,不但可以访问这些对象的共有方法和共有属性,而且还能访问到类(创建时)或对象自身的私有方法和私有属性。在对象创建时通过使用这些特权方法我们可以初始化实例对象的一些属性,因此这些创建对象时调用特权方法还可以看做是类的构造器。

  1. 静态方法、静态属性

在类外面通过点语法定义的方法和属性被称为类的静态共有方法和类的静态共有属性。

  1. 共有方法、共有属性

类通过prototype创建的属性和方法在类实例的对象中是可以通过this访问到的(图prototype新创建的对象的__proto__指向了类的原型所指向的对象),将prototype对象中的属性和方法成为共有属性和共有方法。

var Book = function(id,name,price) {
    // 私有属性
    var num = 1;
    // 私有方法
    function checkId(){};
    
    // 公有属性
    this.id = id;
    // 公有方法
    this.copy = function() {};
    
    // 特权方法
    this.getName = function() {};
    this.getPrice = function() {};
    this.setName = function() {};
    this.setPrice = function() {};
    
    // 构造器
    this.setName(name);
    this.setPrice(price);
}
// 类静态共有属性(对象不能访问)
Book.ischinese = true;
// 类静态共有方法(对象不能访问)
Book.resetTime = function(){};

Book.prototype = {
    // 共有属性
    isJsBook: false,
    // 共有方法
    display: function (){};
}

通过new关键字创建的对象实质是对新对象this的不断赋值,并将prototype指向类的prototype所指向的对象,而类的构造函数外面通过点语法定义的属性方法是不会添加到新创建的对象上去的。因此要想在新创建的对象中使用isChinese就得通过Book类使用而不能通过this,如Book.isChinese,而类的原型prototype上定义的属性在新对象里就可以直接使用,这是因为新对象的prototype和类的prototype指向的是用一个对象。

闭包实现

闭包是有权访问另外一个函数作用域中变量的函数,即在一个函数内部创建另外一个函数。

var Book = (function (){
    // 静态私有变量
    var ischinese = true;
    // 静态私有方法
    var resetTime = function(){};
    function _book(id,name,price) {
        // 私有属性
        var num = 1;
        // 私有方法
        function checkId(){};

        // 公有属性
        this.id = id;
        // 公有方法
        this.copy = function() {};

        // 特权方法
        this.getName = function() {
            return this.name
        };
        this.setName = function(name) {
            this.name = name;
        };

        // 构造器
        this.setName(name);
    }
    _book.prototype = {
        isJsBook: false,
        display: function(){}
    }
    return _book;
})()