封装可以被定义为对对象的内部数据表现形式和实现细节进行隐藏。通过封装可以强制实施信息隐藏。

在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");

利弊

利处

  • 封装保护了内部数据的完整性;
  • 封装使对象的重构更轻松;
  • 弱化模块间的耦合,提高对象的可重用性;
  • 有助于避免命名空间冲突;
  • ……

弊处

  • 私用方法很难测试;
  • 必须与复杂的作用域链打交道,使错误调度更困难;
  • 容易形成过度封装;
  • JavaScript并不原生支持封装,所以在JavaScript中实现封装存在复杂性的问题;
  • ……

『JavaScript』封装的更多相关文章

  1. [原创] 【2014.12.02更新网盘链接】基于EasySysprep4.1的 Windows 7 x86/x64 『视频』封装

    [原创] [2014.12.02更新网盘链接]基于EasySysprep4.1的 Windows 7 x86/x64 『视频』封装 joinlidong 发表于 2014-11-29 14:25:50 ...

  2. 『JavaScript』核心

    弱类型语言 JavaScript是一种弱类型的语言.变量可以根据所赋的值改变类型.原始类型之间也可以进行类型转换.其弱类型的物质为其带来了极大的灵活性. 注意:原始类型使用值传递,复合类型使用引用传递 ...

  3. 『JavaScript』new关键字

    原文 new关键字做了什么 在JavaScript中,使用new关键字后,意味着做了如下四件事情: 创建一个新的对象,这个对象的类型是object: 设置这个新的对象的内部.可访问性和[[protot ...

  4. 『JavaScript』模仿接口

    JavaScript中并没有内置的创建或实现接口的方法.这里将利用JavaScript的灵活性,来实现与接口意义相同的功能. 什么是接口? 接口的好处: 接口提供了一种用以说明一个对象应该具有哪些方法 ...

  5. 转:『代码』JS封装 Ajax级联下拉列表

    在博客园看到一篇不错的AJAX级联下拉列表,觉得不错,特地拿下来 :转载来自:『大雪无痕』 ,原文地址 //当一个 下拉列表 改变时,触发所有联动:(警告:各下拉列表之间 请不要出现 循环依赖) // ...

  6. 『TensorFlow』专题汇总

    TensorFlow:官方文档 TensorFlow:项目地址 本篇列出文章对于全零新手不太合适,可以尝试TensorFlow入门系列博客,搭配其他资料进行学习. Keras使用tf.Session训 ...

  7. 『TensorFlow』批处理类

    『教程』Batch Normalization 层介绍 基础知识 下面有莫凡的对于批处理的解释: fc_mean,fc_var = tf.nn.moments( Wx_plus_b, axes=[0] ...

  8. 『TensorFlow』读书笔记_VGGNet

    VGGNet网络介绍 VGG系列结构图, 『cs231n』卷积神经网络工程实践技巧_下 1,全部使用3*3的卷积核和2*2的池化核,通过不断加深网络结构来提升性能. 所有卷积层都是同样大小的filte ...

  9. 『TensorFlow』命令行参数解析

    argparse很强大,但是我们未必需要使用这么繁杂的东西,TensorFlow自己封装了一个简化版本的解析方式,实际上是对argparse的封装 脚本化调用tensorflow的标准范式: impo ...

随机推荐

  1. POJ 2976 Dropping tests 【01分数规划+二分】

    题目链接:http://poj.org/problem?id=2976 Dropping tests Time Limit: 1000MS   Memory Limit: 65536K Total S ...

  2. GetClassLoader和GetCallerClass的使用

    GetClassLoader是JAVA中用来得到ClassLoader的 JAVA中有以下几种ClassLoader. 1.  Bootstrap ClassLoader - GetClassLoad ...

  3. GPU CUDA编程中threadIdx, blockIdx, blockDim, gridDim之间的区别与联系

    前期写代码的时候都会困惑这个实际的threadIdx(tid,实际的线程id)到底是多少,自己写出来的对不对,今天经过自己一些小例子的推敲,以及找到官网的相关介绍,总算自己弄清楚了. 在启动kerne ...

  4. WSASocket()与Socket()的区别 转

    /**************************************************** WSASocket是Windows专用,支持异步操作:socket是unix标准,只能同步操 ...

  5. EF6.0 对于数据库优 模式 新加功能

    EF6.0相对于5.0新加了很多功能.先看看两个模式的一些特点. 数据库优先(设计者)和代码优先两者的特点: 连接弹性 异步查询和保存 基于代码的配置 数据库命令记录 数据库命令截取 依赖决议 DbS ...

  6. Asset Store 下载的package存在什么地方?

    发现从Asset store下载的packages都不知道放在了什么地方 Windows 7,C:\Users\<username>\AppData\Roaming\Unity\Asset ...

  7. centos7 安装 mysql5.7, 以及安装中遇到的问题

    # wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm# rpm -ivh mysql57-communi ...

  8. Webpack4 学习笔记六 多页面配置和devtool

    webpack 多页配置 webpack可以配置单页应用, 也可以配置多页应用. 区别在于, 单页应用entry入口只有一个, 而多页应用入口有多个 webpack配置: const path = r ...

  9. 如何在match中使用正则表达式

    这是在实现搜索功能的时候遇到的一个问题,在搜索的场景中,会根据搜索框中输入的内容,匹配出包含搜索内容的部分.简单模拟还原使用场景: 首先定义一个遍历 value 用来接收输入的内容 var value ...

  10. 解读JavaScript中的Hoisting机制(js变量声明提升机制)

    hoisting机制:javascript的变量声明具有hoisting机制,JavaScript引擎在执行的时候,会把所有变量的声明都提升到当前作用域的最前面. 知识点一:javascript是没有 ...