javascript设计模式--封装和信息隐藏(上)

简介:   今天博文关注的是javascript中的封装,文章内容来自《pro javascript design patterns》(有兴趣的朋友可以直接去下)和自己对这一问题的理解。   本文分上下两部分,上部讲基本模式(basic patterns):完全暴露法,下划线标记法和使用闭包;下部讲高级模式(Advanced Patterns),如何实现静态方法和属性,常量还有其他一些知识点。

  今天博文关注的是javascript中的封装,文章内容来自《pro javascript design patterns》(有兴趣的朋友可以直接去下)和自己对这一问题的理解。

  本文分上下两部分,上部讲基本模式(basic patterns):完全暴露法,下划线标记法和使用闭包;下部讲高级模式(Advanced Patterns),如何实现静态方法和属性,常量还有其他一些知识点。

 

  封装是面向对象语言很基本也是很有用的特性,虽然javascript也可以称的上是面向对象语言,但他对封装的支持并不是很好,不像其他语言,只要使用private、protected就可以实现。但这并不是说就没有办法了,下面我就介绍下如何在javascript中实现封装。

  一、基本模式(basic patterns),主要包括三种方式:完全暴露法,下划线标记法和使用闭包。(闭包是个很重要,也是很难的概念,有兴趣的朋友可以去网上找资料,我博客里也转载了别人的文章)。

  这里我们以book类作为例子,需要创建和初始化book类。

// Book(isbn, title, author)
var theHobbit = new Book('0-395-07122-4', 'The Hobbit', 'J. R. R. Tolkien');
theHobbit.display(); // Outputs the data by creating and populating an HTML element.

 

  1.完全暴露法:

  创建book类可以用最传统的构造函数方式,

var Book = function(isbn, title, author) {
  if(!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.');
  this.isbn = isbn;
  //代码中 || 的作用是 如果title无值,则会把'No title specified'赋给 this.title。这种方式很好用,大家可以在自己的代码中使用。
  this.title = title || 'No title specified';
  this.author = author || 'No author specified'; }
Book.prototype = {
  //验证isbn函数
  checkIsbn: function(isbn) {
    ...
  },
  //获取isbn
  getIsbn: function() {
    return this.isbn;
  },
  //设置isbn
  setIsbn: function(isbn) {
    if(!this.checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.');
      this.isbn = isbn;
  },
  //获取title
  getTitle: function() {
    return this.title;
  },
  //设置title
  setTitle: function(title) {
    this.title = title || 'No title specified';
  },
  //获取作者
  getAuthor: function() {
    return this.author;
  },
  //设置作者
  setAuthor: function(author) {
    this.author = author || 'No author specified';
  },

  //显示函数
  display: function() {
    ...
  }
};

  代码有点多,我在这里简单讲解下。javascript中创建类和c#,java有点不同,c#,java会把所有方法和属性包在一个类文件里面,比如说

public class book()
{
    private string isbn;
    public string ISBN
    {
        set
{
      this.isbn=value;
     }
     get
     {
      return this.isbn;
     }
  } ...
private bool CheckIsbn(string isdn) { ...... } ...... public void Display() { ...... } }

  javascript也可以用这种方式,但是推荐使用我上面使用的把属性定义到类定义函数(或者叫构造函数),方法定义到prototype对象中,这种做法性能要好些,至于原因大家可以去google。
  上面的js代码想实现的功能是,定义一个book类,类里面包括三个私有变量(或者叫属性)isbn,title,author,一个私有方法checkIsbn,几个公有方法getIsdn,setIsdn,...display。想法是好的,但是现实是残酷的,其实那些私有属性或者方法根本一点都不私有。比如说,theHobbit.isbn = '978-0261103283';你可以用这种方式为isbn赋值,不会报错而且绝对成功。原因就是javascript没有private方式去实现对特定对象的私有化。此外这种实现方式在使用时也会造成困惑,到底类的创建者想暴露哪些属性和方法呢?下面介绍第一种改进办法,下划线标记法。

  2.下划线标记法:

var Book = function(isbn, title, author) {
  // Constructor code.
  this.setIsbn(isbn);   this.setTitle(title);
  this.setAuthor(author);
} Book.prototype = {   
  //验证isbn函数   
  _checkIsbn: function(isbn) {
    ...
  },   
  //获取isbn   
  getIsbn: function() {     
    return this._isbn;   
  },   
  //设置isbn   
  setIsbn: function(isbn) {     
    if(!this._checkIsbn(isbn)) throw new Error('Book: Invalid ISBN.');       
    this._isbn = isbn;   
  },   
  ...  
  //显示函数   
  display: function() {     
  ...   
  }
};

  其实就是在所有想实现私有的属性或者方法前面加了下划线_,没别的操作。这种方法并没有实现真正的私有化,theHobbit._isbn = '978-0261103283';这样操作照样成功,这种方式最大的意义在于告诉类的使用者,作者本意上想暴露哪些对象,不想暴露哪些。但是使用者是否按照作者的想法去做,作者是控制不了的。

  那有没有办法实现真正的私有化呢,答案是有的,就是利用闭包。

  3.使用闭包:

   javascript之所以能实现真正的封装,是和他特有的函数作用域,函数支持内部函数,还有闭包分不开的。大家可以去网上搜集相关知识加深理解。

   下面首先说的就是函数作用域,在javascript中如果在一个函数内部定义了一个变量,那么函数外部是没有办法访问的。其实在javascript中实现私有属性或者方法就是利用了它这一特殊属性。例子:

function foo() {
  var a = 10;
  function bar() {
    a *= 2;
  }
  bar();
  return a;
}

  在上面的例子中函数foo在内部定义了变量a和方法bar,在foo外部是无法访问到a和bar的,但是因为a和bar都定义在foo内部,但bar是可以访问到a的。那么有没有办法能在foo外部访问到bar呢,答案是有的,就是使用闭包。

function foo() {
  var a = 10;
  function bar() {
    a *= 2;
    return a;
  }
  return bar;
}

var baz = foo(); // baz is now a reference to function bar.
baz(); // returns 20.
baz(); // returns 40.
baz(); // returns 80.
var blat = foo(); // blat is another reference to bar.
blat(); // returns 20, because a new copy of a is being used.

  这就是在前面提到的javascript函数支持内部函数。内部函数bar可以访问私有变量a,函数foo又把内部函数bar抛出给baz,baz就可以访问到内部变量a了,这就实现了闭包。大家一看也就明白了,这样其实就实现了私有变量和方法。回到我们前面的book例子,实现如下:

var Book = function(newIsbn, newTitle, newAuthor) { 
  // implements Publication   // Private attributes.   var isbn, title, author;   // Private method.   function checkIsbn(isbn) {     ...   }   // Privileged methods.   this.getIsbn = function() {     return isbn;   };   this.setIsbn = function(newIsbn) {     if(!checkIsbn(newIsbn)) throw new Error('Book: Invalid ISBN.');     isbn = newIsbn;   };   this.getTitle = function() {     return title;   };   this.setTitle = function(newTitle) {     title = newTitle || 'No title specified';   };   this.getAuthor = function() {     return author;   };   this.setAuthor = function(newAuthor) {     author = newAuthor || 'No author specified';   };   // Constructor code.   this.setIsbn(newIsbn);   this.setTitle(newTitle);   this.setAuthor(newAuthor); }; // Public, non-privileged methods. Book.prototype = {   display: function() {     ...   } };

  上述代码就实现了 isbn, title, author和checkIsbn的私有化,外部是决定不能直接访问到的。如需访问 isbn, title, author只能通过对象级的方法getTitle,setTitle...。比如要给isbn赋值,只能用theHobbit.setIsbn = '978-0261103283';,如果你还用theHobbit._isbn = '978-0261103283';,对不起要报错了。

  好了,今天的内容就讲到这里了,希望对大家有帮助。

目录
相关文章
|
6月前
|
前端开发 数据安全/隐私保护
crypto-js中AES的加解密封装
文章介绍了如何在前端使用crypto-js库进行AES加密和解密,提供了加解密的函数封装示例,并演示了如何加密和解密字符串或对象。
442 1
crypto-js中AES的加解密封装
|
1月前
|
设计模式 JavaScript 算法
浅谈几种js设计模式
设计模式是软件开发中的宝贵工具,能够提高代码的可维护性和扩展性。通过单例模式、工厂模式、观察者模式和策略模式,我们可以解决不同场景下的实际问题,编写更加优雅和高效的代码。
29 8
|
2月前
|
设计模式 数据安全/隐私保护
Next.js 实战 (七):浅谈 Layout 布局的嵌套设计模式
这篇文章介绍了在Next.js框架下,如何处理中后台管理系统中特殊页面(如登录页)不包裹根布局(RootLayout)的问题。作者指出Next.js的设计理念是通过布局的嵌套来创建复杂的页面结构,这虽然保持了代码的整洁和可维护性,但对于特殊页面来说,却造成了不必要的布局包裹。文章提出了一个解决方案,即通过判断页面的skipGlobalLayout属性来决定是否包含RootLayout,从而实现特殊页面不包裹根布局的目标。
123 33
|
7月前
|
存储 前端开发 JavaScript
javascript 异常问题之为自定义异常提供丰富的上下文信息如何实现
javascript 异常问题之为自定义异常提供丰富的上下文信息如何实现
|
4月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
67 2
|
5月前
|
机器学习/深度学习 自然语言处理 JavaScript
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
在信息论、机器学习和统计学领域中,KL散度(Kullback-Leibler散度)是量化概率分布差异的关键概念。本文深入探讨了KL散度及其相关概念,包括Jensen-Shannon散度和Renyi散度。KL散度用于衡量两个概率分布之间的差异,而Jensen-Shannon散度则提供了一种对称的度量方式。Renyi散度通过可调参数α,提供了更灵活的散度度量。这些概念不仅在理论研究中至关重要,在实际应用中也广泛用于数据压缩、变分自编码器、强化学习等领域。通过分析电子商务中的数据漂移实例,展示了这些散度指标在捕捉数据分布变化方面的独特优势,为企业提供了数据驱动的决策支持。
477 2
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
|
5月前
|
设计模式 JavaScript 前端开发
JavaScript设计模式--访问者模式
【10月更文挑战第1天】
55 3
|
5月前
|
JavaScript 前端开发 UED
JavaScript 地址信息与页面跳转
JavaScript 地址信息与页面跳转
98 1
|
5月前
|
前端开发 JavaScript Go
JS基础:输出信息的5种方式详解
JS基础:输出信息的5种方式详解
75 1
|
6月前
|
设计模式 JavaScript
JS发布订阅模式封装(纯手工)
发布订阅模式是JS常用的设计模式,在面试中也会经常遇到,以下是我的手写实现方式,经测试效果不错,小伙伴们们可以直接拷贝使用。

热门文章

最新文章