一、封装
面向对象编程思想其中的一个特点就是封装,通俗的讲法就是把需要的功能方向在一个对象里。遗憾的是,对于JS这种解释性的弱类型语言没有经典强类型语言中那样通过class等关键字实现类的封装方法,js中都是通过一些特性模仿实现的,虽然这是个弊端,但也带来了极高的灵活性。
我们看一个Book类是如何通过JS实现的:
1 // 写法1 2 var Book = function (id, name, pirce) { 3 this.id = id 4 this.name = name 5 this.price = pirce 6 } 7 8 /* 9 * 以下两种方式不可混用 10 */ 11 12 // 也可以通过在类的原型对象prototype上添加属性和方法,有两种方式 13 // 一种是一一为原型对象属性赋值 14 Book.prototype.display = function () { 15 // ... 16 } 17 18 // 一种是将一个对象赋值给类的原型对象 19 Book.prototype = { 20 display: function () { 21 // ... 22 } 23 }
这样,我们就将所需要的方法和属性都封装在我们抽象的Book类里面,当使用功能方法时,我们不能直接使用Book类,需要用new关键字来实例化新的对象,并通过点语法来访问对象的属性或者方法。比如:
1 var book = new Book(10, '书', '50') 2 console.log(book.name) // 书
从代码可以看出,我们通过this添加了属性,通过prototype添加了方法,那么这两者有什么区别?
通过this添加的属性和方法是在当前对象上添加的,然而JS是一种基于原型的prototype的语言,所以每次创建一个新对象时,通过prototype继承的方法并不是对象自身的,所以在使用这些方法时,需要通过prototype一级一级查找的来,而通过this定义的属性或者方法是该对象自身所拥有的,所以我们每次创建一个新对象时,this指向的属性和方法都会得到相应的创建。
二、属性与方法封装
在OOP中,既然是类,必定有私有属性,私有方法,共有属性,共有方法等这些概念,那么JS中又是如何去实现呢?
由于JS的函数作用于,声明在函数内部的变量以及方法在外界是访问不到的,通过次特性可以创建类的私有变量以及私有方法,然而在函数内部通过this创建的属性和方法,在类创建对象时,每个对象自身都拥有一份并且可以在外部访问到,因此这些属性和方法可以看作为共有的,还是Book为例:
1 // 私有属性与私有方法,特权方法,对象共有属性和对象公有方法 2 var Book = function (id, name, price) { 3 // 私有属性 4 var num = 1 5 // 私有方法 6 function checkId () { 7 // ... 8 } 9 // 特权方法 10 // 所谓的特权方法,是既可以被外部访问到,又可以访问类内部的私有属性与方法的方法 11 this.getName = function () { 12 // ... 13 } 14 this.getPrice = function () { 15 // ... 16 } 17 this.setName = function () { 18 // ... 19 } 20 this.setPrice = function () { 21 // ... 22 } 23 // 对象公有属性 24 this.id = id 25 // 对象公有方法 26 this.copy = function () { 27 // ... 28 } 29 30 }
而在OOP中,还有两个概念是:静态属性与静态方法,这两种东西都属于类所有,而不属于每一个对象,调用也只能通过类名加上点语法来使用,那么JS中如何实现呢?
其实很简单,我们可以在类定义的外面,通过点语法定义属性以及方法,这样,通过new关键字创建时,这写在类外面通过点语法添加的属性和方法是不会被执行到的,因而只能被类本身所调用,我们也就达到了模仿静态属性与方法的目的。
1 // 类静态公有属性(对象不能访问) 2 Book.isChinese = true 3 // 类静态公有方法(对象不能访问) 4 Book.getIsChinese = function () { 5 return Book.isChinese 6 }