封装

封装数据

在许多语言的对象系统中,封装数据是由语法解析来实现的,这些语言也许提供了 private、 public、protected 等关键字来提供不同的访问权限。例如:java

但在js里面,并没有提供这些关键字的支持,我们只能通过作用域来模拟实现封装性。(ES6 let除外)

var myTest = (function() {var _name ='jason';return {getName: function(){return _name;}}
})()
console.log(myTest.getName()); // 输出:jason
console.log(_name); // 输出:_name is not defined
复制代码

这里,我们定义了一个自执行函数(什么叫自执行函数?参考这篇文章),函数内部定义了一个变量_name,函数return一个对象出去(也叫模块模式),向外部暴露了一个getName函数,这里的_name变量就被封装在了myTest函数内部。

上文说的是封装数据,在js里,不光数据可以封装,还可以封装实现、封装类型,封装变化等,封装使得对象之间的耦合变得松散,对象之间只通过暴露的 API 接口来通信。

原型模式和基于原型继承的JavaScript对象系统

在java中,对象必须由类创建而来,而在js中,对象却是通过原型继承的方式得来的,在原型编程的思想中,类并不是必需的,对象未必需要从类中创建而来, 一个对象是通过克隆另外一个对象所得到的。

原型模式不单是一种设计模式,也被称为一种编程泛型。

使用克隆的原型模式

从设计模式的角度讲,原型模式是用于创建对象的一种模式,如果我们想要创建一个对象, 一种方法是先指定它的类型,然后通过类来创建这个对象。原型模式选择了另外一种方式,我们 不再关心对象的具体类型,而是找到一个对象,然后通过克隆来创建一个一模一样的对象。 原型模式的实现关键,是语言本身是否提供了 clone 方法。ECMAScript 5 提供了 Object.create 方法,可以用来克隆对象。代码如下:

var Plane = function(){ this.blood = 100;this.attackLevel = 1;this.defenseLevel = 1;
};
var plane = new Plane();
plane.blood = 500;
plane.attackLevel = 10;
plane.defenseLevel = 7;
var clonePlane = Object.create( plane );
console.log( clonePlane ); // 输出:Object {blood: 500, attackLevel: 10,defenseLevel: 7}在不支持 Object.create 方法的浏览器中,则可以使用以下代码:Object.create = Object.create || function( obj ){var F = function(){};F.prototype = obj;return new F();
}
复制代码

原型编程范型的一些规则

  • 所有的数据都是对象。
  • 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它。
  • 对象会记住它的原型。
  • 如果对象无法响应某个请求,它会把这个请求委托给它自己的原型。

JavaScript中的原型继承

这里我们来根据上面的范式来整理一下js中遵循的规则

所有的数据都是对象

在js中,除了undefined之外,所有数据都是对象,number、boolean、string 这几种基本类型数据也可以通过“包装类”的方式变成对象类型数据来处理。那么根据原型规则,这些对象一定有个根对象,这个对象就是Object.prototype,Object.prototype 对象是一个空的 对象。我们在 JavaScript 遇到的每个对象,实际上都是从 Object.prototype 对象克隆而来的, Object.prototype 对象就是它们的原型。

var obj1 = new Object();
var obj2 = {};console.log( Object.getPrototypeOf( obj1 ) === Object.prototype ); // 输出:true
console.log( Object.getPrototypeOf( obj2 ) === Object.prototype ); // 输出:true
复制代码
要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并克隆它

js中克隆是引擎内部实现的,我们不用去关心他是如何实现的,我们只要知道使用var obj1 = new Object()或者var obj2 = {},引擎就会从Object.prototype克隆一个对象出来。

接下来我们看看如何使用new运算符得到一个对象

var Person = function(name) {this.name = name;this.getName = function() {return this.name;}
}var p = new Person('jason');console.log(p.name);
console.log(p.getName());
console.log(Object.getPrototypeOf(p) === Person.prototype); // 输出true
复制代码

在 JavaScript 中没有类的概念,这句话我们已经重复过很多次了。但刚才不是明明调用了newPerson()吗?

在这里 Person 并不是类,而是函数构造器,JavaScript 的函数既可以作为普通函数被调用, 7 也可以作为构造器被调用。当使用 new 运算符来调用函数时,此时的函数就是一个构造器。 用 new 运算符来创建对象的过程,实际上也只是先克隆 Object.prototype 对象,再进行一些其他额 外操作的过程。

对象会记住它的原型

JavaScript 给对象提供了一个名为__proto__的隐藏属性,某个对象的__proto__属性默认会指 向它的构造器的原型对象,即{Constructor}.prototype。 我们通过代码来验证:

var objA = {name: 'jason'
}console.log(objA.__proto__ === Object.prototype); //true
复制代码

再来

var objB = function(age) {this.age = age;
}var b = new objB();console.log(b.__proto__ === objB.prototype); //true
复制代码

实际上,__proto__就是对象跟“对象构造器的原型”联系起来的纽带 切记这句话,对未来理解js原型链很有帮助。

如果对象无法响应某个请求,它会把这个请求委托给它的构造器的原型

虽然 JavaScript 的对象最初都是由 Object.prototype 对象克隆而来的,但对象构造器的原型并不仅限于 Object.prototype 上,可以动态指向其他对象。

var obj = { name: 'sven' };
var A = function(){};A.prototype = obj;
var a = new A();
console.log(a.__proto__ === obj); //true
console.log(a.name); // 输出:sven
复制代码

上面的代码中,第一行和第二行本没有任何关联,obj是个对象字面量创建的对象,A是个空方法,在第三行代码执行之前,obj__proto__指向Object.prototypeAprototype指向自身的构造器,A.prototype = obj;将引用指向了obj,所以在代码执行完后,对象a的原型指向obj,虽然a本身没有name属性,但原型上拥有name属性

总结

现在,让我们来总结一下js创建对象的几种方式:

  1. 对象字面量
var obj = {};
复制代码
  1. 通过对象构造器创建
var Co = function(){};
var obj = new Co();
复制代码
  1. 通过Object.create();创建(ES5以后版本支持)
var Co = function(){};
var obj = Object.create(Co);
复制代码
  1. 通过class创建(ES6以后版本支持)
class An{constructor(name){this.name = name;}getName() {return this.name;}
}class Dog extends Animal { constructor(name) {super(name); }speak() {return "woof";}
}var dog = new Dog("Scamp");
console.log(dog.getName()); // Scamp
console.log(dog.speak()); // woof
复制代码

上面的几种创建对象的方式有本质的区别,这里先不做详细说明,后续学完作用域和闭包后再统一说明。

javascript设计模式与开发实践(二)- 封装和原型模式相关推荐

  1. JavaScript设计模式与开发实践---读书笔记(6) 代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问. 代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象 ...

  2. JavaScript设计模式与开发实践(网课学习)

    Js设计模式与开发实践 面向对象 5大设计原则 23种设计模式(实际只有21种) 设计模式主要分为下面三大类 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模 ...

  3. 《JavaScript设计模式与开发实践》模式篇(12)—— 装饰者模式

    在传统的面向对象语言中,给对象添加功能常常使用继承的方式,但是继承的方式并不灵活, 还会带来许多问题:一方面会导致超类和子类之间存在强耦合性,当超类改变时,子类也会随之 改变;另一方面,继承这种功能复 ...

  4. JavaScript设计模式与开发实践——JavaScript的多态

    "多态"一词源于希腊文polymorphism,拆开来看是poly(复数)+ morph(形态)+ ism,从字面上我们可以理解为复数形态. 多态的实际含义是:同一操作作用于不同的 ...

  5. 《JavaScript设计模式与开发实践》阅读摘要

    <JavaScript设计模式与开发实践>作者:曾探 系统的介绍了各种模式,以及js中的实现.应用,以及超大量高质量代码,绝对值得一读 面向对象的js 静态类型:编译时便已确定变量的类型 ...

  6. JavaScript设计模式与开发实践 | 02 - this、call和apply

    this JavaScript的this总是指向一个对象,至于指向哪个对象,是在运行时基于函数的执行环境的动态绑定的,而非函数被声明时的环境. this的指向 this的指向大致可以分为以下4类: 作 ...

  7. 《JavaScript设计模式与开发实践》原则篇(3)—— 开放-封闭原则

    在面向对象的程序设计中,开放封闭原则(OCP)是最重要的一条原则.很多时候,一个程序具有良好的设计,往往说明它是符合开放封闭原则的. 当需要改变一个程序的功能或者给这个程序增加新功能的时候,可以使用增 ...

  8. JavaScript设计模式与开发实践系列之单例模式

    本系列为<JavaScript设计模式与开发实践>(作者:曾探)学习总结,如想深入了解,请支持作者原版 单例模式 实现单例模式 单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的 ...

  9. JavaScript设计模式与开发实践 - 单例模式

    引言 本文摘自<JavaScript设计模式与开发实践> 在传统开发工程师眼里,单例就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返 ...

  10. javascript设计模式(javascript设计模式与开发实践读书笔记)

    javascript设计模式(javascript设计模式与开发实践读书笔记) 单例模式 策略模式 代理模式 迭代器模式 发布-订阅模式 命令模式 组合模式 模板方法模式 享元模式 职责链模式 中介者 ...

最新文章

  1. C/C++ 编程规范(02)— 标识符命名
  2. java编写socket使用bufferedReader.readLine()问题研究
  3. 通过TStringList保存csv文件,只要循环.Add表格里面的每行记录进去,保存即可
  4. linux下tty,控制台,虚拟终端,串口,console(控制台终端)详解
  5. 全球及中国衣柜香氛市场投资份额与营销潜力研究报告2022版
  6. boost::callable_traits的is_const_member的测试程序
  7. malloc,colloc,realloc内存分配,动态库,静态库的生成与调用
  8. 必看!互联网开发模式的经验之谈
  9. Asp.net Core中SignalR Core预览版的一些新特性前瞻,附源码(消息订阅与发送二进制数据)
  10. 领域应用 | 金融资管领域知识图谱的构建和应用
  11. 音视频开发(8)---nginx+nginx-rtmp-module+ffmpeg搭建流媒体服务器
  12. python下载_安装_配置_以及第一行python程序---python工作笔记009
  13. gin mysql_golang+gin+mysql构建RESTful API
  14. 用计算机绘制阀体各零件步骤,计算机绘图课程设计.doc
  15. LED产品认证和检测
  16. 做高级PPT的一点经验
  17. 【算法】两矩形相交的判定
  18. python 删除字典none_python – 从字典中删除NoneTypes
  19. python转义是什么意思_什么是python转义字符?看看人士如何理解它.
  20. 妙味课堂:JavaScript初级--第11课:字符串、查找高亮显示

热门文章

  1. REM——适合移动开发的自适应方案
  2. 阿里开源分布式事务解决方案 Fescar 全解析
  3. phpmyadmin error:#2002 - 服务器没有响应
  4. boost::asio::streambuf 基本用法和注意事项
  5. Linux tree命令
  6. 《告别失控:软件开发团队管理必读》一一2.6 代系特点
  7. 编程问题之:x=xamp;(x-1)
  8. .NET连接SAP系统专题:C#调用RFC代码(三)
  9. 3.请执行命令取出linux中eth0的IP地址(考试题答案系列)
  10. PHP 4.4.7 中用 PEAR 类库操作 ZIP 压缩文件