数字营销 · Web开发 · 基础设施

PHP封装和JavaScript封装的比较

通过同一个“上班族”示例,对比 PHP 的访问控制机制与 JavaScript 闭包实现的数据封装方式。

隐藏对象的属性和实现细节,仅对外公开接口,控制程序中属性读取和修改的访问级别。

这就是通常所说的封装。

我们知道,在 Java、C++ 这类严格的面向对象语言中,对象的封装相对比较容易实现。那么在 PHP 和 JavaScript 中,如何对一个对象进行封装,并隐藏对象内部的属性和实现细节呢?

下面通过同一个例子,分别看看 PHP 和 JavaScript 中的实现方式。

PHP中的封装

由于 PHP 提供了 class 关键字,可以比较方便地定义一个类:

<?php

class Workers {

public $age;
public $name;
public $sex;

private $wage=5000;

public function __construct($a, $b, $c){
$this->age =$a;
$this->name =$b;
$this->sex =$c;
}

public function saypay(){
echo $this->wage;
}
}
?>

这里定义了一个“上班族”类。

这个类有四个属性:

  • 年龄
  • 姓名
  • 性别
  • 工资

一般来说,前三个属性可以公开访问,而工资可能属于比较私密的信息,不希望任何外部代码都可以直接访问或修改。

因此,我们使用 "private $wage = 5000;" 将工资定义为私有属性。

当实例化一个“小明”对象后:

<?php
$xiaoming = new Workers(25, "小明", "男");
echo $xiaoming->age;
?>

可以直接访问年龄。

但是如果直接访问工资:

<?php
echo $xiaoming->wage;
?>

就会提示无法访问,因为 wage 是一个私有属性。

这样就保护了对象内部的数据。

但是,这里又会出现一个问题。

私有属性并不意味着任何情况下都不能访问。

例如,小明每个月总需要知道自己的工资是多少。这时候,就可以通过类提供的一个公共方法来访问内部的私有属性:

<?php
echo $xiaoming->saypay();
?>

这里的 saypay() 就相当于一个对外公开的接口。

外部代码不能直接访问 "$xiaoming->wage" 但是可以通过 "$xiaoming->saypay()", 获取工资信息。

这样,真正的数据仍然保存在对象内部,而外部只能通过类提供的方法进行访问。

JavaScript中的封装

那么,在 JavaScript 中如何实现类似的效果呢?

JavaScript 当时并没有 PHP 这样直接通过 private 关键字定义私有属性的方式,因此实现思路有所不同。

还是使用刚才的“上班族”例子:

function Workers(a, b, c){
this.age =a;
this.name =b;
this.sex =c;

var wage=5000;

this.saypay =function(){
return wage;
};
}

var xiaoming=newWorkers(25, "小明", "男");
alert(xiaoming.age);
alert(xiaoming.name);
alert(xiaoming.sex);
alert(xiaoming.wage);
alert(xiaoming.saypay());

这里:this.age, this.name, this.sex 都是对象的公开属性,因此可以直接访问, alert(xiaoming.age);

但是工资 var wage=5000 只是 Workers 函数内部的一个局部变量。

因此,外部无法直接访问:alert(xiaoming.wage); 结果会是 undefined

但是,saypay() 函数可以访问这个内部变量:

this.saypay =function(){
return wage;
};

所以:

alert(xiaoming.saypay());

可以正常获取工资。

这里利用的其实就是 JavaScript 的作用域和闭包特性。

两种方式有什么不同?

两个例子实现出来的效果比较相似:

对象内部有一些属性不希望被外部直接访问,而是通过指定的方法进行读取和操作。

但是它们的实现原理并不一样。

PHP

PHP 通过访问控制关键字:

public
protected
private

直接控制对象属性和方法的访问权限。

例如:

private $wage = 5000;

外部代码无法直接访问。

JavaScript

JavaScript 这个例子中,并没有真正把 wage 挂载到对象上:

var wage = 5000;

它只是构造函数内部的局部变量。

外部无法直接访问这个变量,但是通过内部定义的方法,仍然可以访问它:

this.saypay =function(){
returnwage;
};

因此,两个例子虽然最终实现了类似的效果,但底层思路并不相同。

私有属性也可以通过接口修改

对象内部受保护的属性,有时候不仅需要读取,也需要进行修改。

例如,小明刚开始的工资是:5000

随着工作经验和技术水平的提高,工资可能会发生变化。

这时候,同样可以定义一个公开的方法来修改工资:

functionWorkers(a, b, c){

this.age =a;
this.name =b;
this.sex =c;

var wage=5000;

this.saypay =function(){
returnwage;
};

this.setpay =function(newwage){
wage=newwage;
};
}

然后:

varxiaoming=newWorkers(25, "小明", "男");

alert(xiaoming.saypay());
// 5000
xiaoming.setpay(8000);
alert(xiaoming.saypay());
// 8000
//外部代码仍然不能直接修改:
xiaoming.wage =8000;
//而是需要通过:
xiaoming.setpay(8000);

这个方法进行修改。

这样,对象内部的数据访问和修改都可以集中控制。

这也是封装的一个重要意义:

不一定要完全禁止外部访问,而是控制外部应该通过什么方式访问。

评论0

欢迎分享你的看法,也欢迎补充不同的实践经验。