这篇文章主要帮助大家理解学习 javascript 封装,通过封装可以强制实施信息隐藏,本文为大家分析了封装的利弊,感兴趣的小伙伴们可以参考一下
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
封装可以被定义为对对象的内部数据表现形式和实现细节进行隐藏。通过封装可以强制实施信息隐藏。
在 JavaScript 中,并没有显示的声明私有成员的关键字等。所以要想实现封装 / 信息隐藏就需要从另外的思路出发。我们可以使用闭包的概念来创建只允许从对象内部访问的方法和属性,来达到封装的要求。
基本方式
一般来说,我们学用的有三种方法来达到封装的目的。
使用 this.XXX 来声明一个变量,然后再声明 getXXX、setXXX 等取值、赋值的方法。
使用 this._XXX 来声明一个变量,然后再声明 getXXX、setXXX 等取值、赋值的方法。
利用 "函数作用域" 这一个概念来做。
1. 门户大开型
- var Book = function(isbn,title,author){
- this.setIsbn(isbn);
- this.setTitle(title);
- this.setAuthor(author);
- };
- Book.prototype = {
- setIsbn: function(isbn){
- this.isbn = isbn;
- },
- getIsbn: function(){
- return this.isbn;
- },
- setTitle: function(title){
- this.title = title;
- },
- getTitle: function(){
- return this.title;
- },
- setAuthor: function(author){
- this.author = author;
- },
- getAuthor: function(){
- return this.author;
- }
- };
使用这种方法实现的封装,虽然实现了取值器与赋值器以保护私有属性。但是在实际使用中,私有属性依然可以从外部访问,所以从根本上讲,没有实现封装。
2. 用命名规范进行区别
- var Book = function(isbn,title,author){
- this.setIsbn(isbn);
- this.setTitle(title);
- this.setAuthor(author);
- };
- Book.prototype = {
- setIsbn: function(isbn){
- this._isbn = isbn;
- },
- getIsbn: function(){
- return this._isbn;
- },
- setTitle: function(title){
- this._title = title;
- },
- getTitle: function(){
- return this._title;
- },
- setAuthor: function(author){
- this._author = author;
- },
- getAuthor: function(){
- return this._author;
- }
- };
使用这种方法与第一种类似,区别在于使用不同的命名来保护私有属性的使用。但是,从实际应用来说其仍然没有实现封装。
3. 使用函数作用域
- var Book = function(newIsbn,newTitle,newAuthor){
- var isbn,title,author;
- this.setIsbn=function(newIsbn){
- isbn = newIsbn;
- };
- this.getIsbn=function(){
- return isbn;
- };
- this.setTitle=function(newTitle){
- title = newTitle;
- };
- this.getTitle=function(){
- return title;
- };
- this.setIsbn=function(newAuthor){
- author = newAuthor;
- };
- this.getIsbn=function(){
- return author;
- };
- }
由于在 JavaScript 的函数中声明的变量是有作用域的,所以使用这种方法可以避免在外部直接访问私有属性。基本达到封装所要求的内容。
这里要注意的是,我们在函数的内部,可以使用 this.XXX 以及 var 来声明变量。区别是使用 this.XXX 声明的变量在外部是可以访问的。使用 var 声明的变量,由于受到函数作用域的保护,在函数的外部是无法直接访问的。
4. 使用函数作用域的变形
- var Book = (function(){
- // ...其他静态方法
- return function(newIsbn,newTitle,newAuthor){
- var isbn,title,author;
- this.setIsbn=function(newIsbn){
- isbn = newIsbn;
- };
- this.getIsbn=function(){
- return isbn;
- };
- this.setTitle=function(newTitle){
- title = newTitle;
- };
- this.getTitle=function(){
- return title;
- };
- this.setIsbn=function(newAuthor){
- author = newAuthor;
- };
- this.getIsbn=function(){
- return author;
- };
- };
- })();
这种方法是直接返回一个构造器的执行。且这里的构造器是一个内嵌函数。
这种方法的优点是 "在内存中只会存在一份。因为其他静态方法被声明在构造器之外,所以它们不是特权方法。"
判断一个方法是否应该被设计为静态方法的原则是 "这个方法是否会访问私有属性"。如果它不需要,那么将其设计为静态方法会更有效率,因为它只会被创建一份。
常量
我们可以使用 "只有取值器,没有赋值器" 的方式来实现常量。
- // 1.
- var Book = function(){
- var constants = ["key1": "1","key2": "2","key3": "3"];
- this.getConstant = function(key){
- return constants[key];
- };
- };
- Book.getConstant("key1");
- // 2.
- var Book = (function(){
- var constants = ["key1": "1","key2": "2","key3": "3"];
- var con = function(){};
- con.getConstant = function(name){
- return constants[name];
- };
- return con;
- })();
- Book.getConstant("key1");
利弊
1、利处
封装保护了内部数据的完整性;
封装使对象的重构更轻松;
弱化模块间的耦合,提高对象的可重用性;
有助于避免命名空间冲突;
……
2、弊处
私用方法很难测试;
必须与复杂的作用域链打交道,使错误调度更困难;
容易形成过度封装;
JavaScript 并不原生支持封装,所以在 JavaScript 中实现封装存在复杂性的问题;
来源: http://www.phperz.com/article/17/0221/267024.html