这些天我正在学习JS,我无法在the book的第52页上吸收这种功能模式。
功能
到目前为止,我们看到的继承模式的一个弱点是我们没有隐私。 对象的所有属性都是可见的。我们没有私有变量,也没有 私人方法。有时这无关紧要,但有时它很重要。令人沮丧的是,一些不知情的程序员采用了假装的模式 隐私的。如果他们有一个他们希望私有的属性,他们给它一个奇怪的名字,希望代码的其他用户会假装他们不能 看到看起来很奇怪的成员。幸运的是,我们有更好的选择 模块模式的应用。
我们首先创建一个会产生对象的函数。我们会给它一个名字 以小写字母开头,因为它不需要使用新的前缀。该 功能包含四个步骤:
- 它会创建一个新对象。有很多方法可以制作一个物体。它可以成为一个 object literal,或者它可以使用新前缀调用构造函数,或者它可以 使用Object.beget方法从现有对象生成新实例,或 它可以调用任何返回对象的函数。
- 它可选地定义私有实例变量和方法。这些只是普通的 vars of the function。
- 它用方法扩充了这个新对象。这些方法将具有特权 访问第二步中定义的参数和变量。
- 返回该新对象。
醇>
这是一个功能构造函数的伪代码模板(添加了粗体文本 强调):
var constructor = function (spec, my) { var that, //other private instance variables; my = my || {}; // Add shared variables and functions to my that = a new object; // Add privileged methods to that return that; }spec对象包含构造函数需要创建的所有信息 实例。 spec 的内容可以复制到私有变量中或转换 通过其他功能。或者方法可以从 spec 中访问信息 需要它。 (简化是用单个值替换spec。这在以下情况下很有用 正在构造的对象不需要整个 spec 对象。)
任何人都可以解释,那里发生了什么(以外行人的话说)以及这种模式有用的地方?
答案 0 :(得分:2)
注意:虽然你所提到的这本书确实是一本非常有用的书,但却非常古老。在最新版本的JavaScript中,一些“好”(甚至“坏”)部分已被更好的替代品和功能所取代。
到目前为止,我们看到的继承模式的一个弱点是 我们没有隐私。对象的所有属性都是可见的。我们没有 私有变量,没有私有方法。
Javascript对象具有“属性”,可以是其他对象或函数。考虑:
var obj = {a: 1, do: function(){console.log('done');} }
没有什么能阻止您拨打obj.a = 5
或obj.done()
。
但有人可能反驳说,这不是创建对象的好方法。我们最好有一个原型或类,我们可以从中创建新实例:
function Animal(name) {
this._name = name;
}
Animal.prototype.print = function(){console.log(this._name)};
或更新的JavaScript版本:
class Animal {
constructor(name){
this._name = name;
}
print(){
console.log(this._name);
}
}
令人沮丧的是,一些不知情的程序员采用了一种模式 假装隐私。如果他们有自己想要的财产 私人,他们给它一个奇怪的名字,希望其他 代码的用户会假装他们看不到奇怪的样子 成员。
这是对上述代码的评论。在声明JavaScript类或函数时,没有官方的,标准的,“傻瓜证明和语法优雅”保持实例变量私有的方式。也就是说,一种简单,干净的方式来声明一个只能在该类或原型(See this answer)中定义的方法访问的变量。因此,人们遵循一些商定的模式,其中一个模式为变量名称添加前缀_
。这实际上没有为类实例的内部变量提供隐私。
随着module system的出现,人们可以在单独的文件/容器中编写JavaScript代码,并选择仅对外部世界可见的特定对象。一个CommonJS例子:
Animal.js:
const props = new WeakMap();
class Animal {
constructor(name){
props.set(this,{});
props.get(this).name = name;
}
set age(n){
props.get(this).age = age;
}
function print(){
console.log(props.get(this));
}
}
module.exports = Animal;
上面是其中一个声明具有私有属性的类的方法,除非故意泄露,否则无法从外部访问。注意对象props
如何不导出到外部世界。
幸运的是,我们在应用程序中有更好的选择 模块模式。
您可能认为上述模块代码实际上是本文的含义,但上述实现是使用最新功能的较新版本。文本中的点的旧学校方式是暴露对象创建者(a.k.a工厂)功能。在创建者函数内部和创建对象外部声明的所有内容都是设计私有的:
function createAnimal(name){
var age = 0;
var animal = {};
animal.setAge = function(a){age = a;};
animal.getName = function(){return name;};
animal.print = function(){console.log({'name':name,'age':age});};
}
这里的继承是对超级创建者的调用并修改超级实例:
function createDog(name, color){
var breed = 'unknown';
var dog = createAnimal(name);
dog.setBreed = function(b){breed = b;};
}
答案 1 :(得分:0)
基本上,这个想法是隐藏隐藏中的私有变量。被关闭的变量是(未示出)“其他私有实例变量”,实际关闭这些变量的方法是(也未示出)“特权方法”。
例如,使用此功能:
var createBoard = function (rows, cols) {
var cells = [];
var board = {};
for (var i = 0; i < rows; i++) {
cells[i] = [];
for (var j = 0; j < cols; j++) {
cells[i][j] = { player: null };
}
}
board.play = function (row, col, player) {
if (cells[row][col].player === null) {
cells[row][col].player = player;
}
};
board.getPlayer = function (row, col) {
return cells[row][col].player;
};
return board;
};
让我们假设我们调用此函数来创建一个8x8游戏板:
var board = createBoard(8,8);
board.play(1,2,"Player1");
console.log(board.getPlayer(1,2));
board.play(1,2,"Player2"); // Doesn't actually do anything
// Note this code has no direct access to cells[][] except via the two
// methods we defined on the board object.
在这种情况下,我们返回一个棋盘对象。董事会内部可以访问一个单元格数组,但我们不会让任何人修改它,除非使用我们的两种方法,play(只有在以前没有占用时占用一个板空间)和一个getPlayer方法返回给定的给定空间。 Cells [] []对此代码的用户完全隐藏 - 他们无法通过直接更改我们的单元格来作弊。
答案 2 :(得分:0)
JavaScript是一种基于原型的基于对象的语言,而不是基于类的。 1
将其与基于PHP,Java等类的面向对象语言进行比较。在这些语言中,可以定义类,并且成员变量可以在类的内部和外部具有各种可见性。例如,PHP的visibility设置为三个级别: public , protected 或 private 。
声明为public的类成员可以随处访问。声明受保护的成员只能在类本身和继承的类中访问。声明为私有的成员只能由定义该成员的类访问。 2
class MyClass {
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function printHello() {
echo $this->public;
echo $this->protected;
echo $this->private;
}
}
$obj = new MyClass();
echo $obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
但是在JavaScript中,我们并没有真正拥有私有变量的概念(在同一意义上)。这就是作者在描述模块模式时所谈论的内容。
因此,如果我们想在Javascript中创建一个类似的构造,我们可以做这样的事情:
var MyClass = function (rows, cols) {
//this could be used in prototype functions
var private = 'Private';
var members = {
public: 'Public';
getHello: function() {
return 'MyClass _ ' + private;
}
};
return members;
};