JavaScript的对象实现
类似Java,可以使用JavaScript来模拟类以及对象的实现。
1. 对象定义
function Person() {
// 就相当于一个Person类
// 私有属性
var name = "张三";
// 私有方法
var _show_pr = function() {
alert(name);
}
// 公有属性用this关键字声明
this.age = 18;
// 公有方法也用this关键字
this._show_pu = function() {
// 如果公有方法里面访问的是私有属性,直接写属性名
// 如果访问的是公有属性,使用this.属性名
alert(name + " : " + this.age);
}
}
var p = new Person();
// 访问公有方法和属性
p._show_pu();
alert(p.age);
2. 静态属性与静态方法的模拟
// 静态成员不可以用对象调用
function Person() {}
Person.name = "张三"; // 定义一个静态属性,[类名.属性名]来定义
Person.show = function() {
alert("static");
}
var p = new Person();
alert("用对象访问" + p.name); // 使用new出来的对象无法访问到静态的属性和方法
alert("用类名访问" + Person.name); // 访问静态属性使用类名调用
Person.show(); // 访问静态方法使用类名调用
3. 构造器的模拟
function Person1(){
this.name = "张三";
this.age = 18;
}
var p1 = new Person1(); // 使用无参构造函数创建对象
alert("无参构造器:" + p1.name + " : " + p1.age);
function Person2(name, age){
this.name = name;
this.age = age;
}
var p2 = new Person2("小明", 20); // 使用有参构造函数创建对象
alert("有参构造器:" + p2.name + " : " + p2.age);
JavaScript的扩展原型
原型扩展
prototype 属性使JavaScript有能力向对象添加属性和方法。
比如:给array对象添加一个getMax方法。
Array.prototype.getMax = function() {
var _max = this[0]; //取数组的第一个元素
for (var i = 0; i < this.length; i++) {
if (_max < this[i]) {
_max = this[i];
}
}
return _max;
}
var arr = new Array(1, 3, 5, 7, 9, 342, 340, 406, 66, 60);
alert(arr.getMax());
产生的问题
原型扩展虽然让JavaScript框架有了非常好的扩展性,但是却非常容易产生属性共享问题。
function Person() {}
Person.prototype.arr = [1, 3];
var p1 = new Person();
p1.arr.push(111);
alert(p1.arr); // [1, 3, 111]
var p2 = new Person();
alert(p2.arr); // [1, 3, 111]
p1为其属性添加元素,结果p2的属性也为之联动。
JavaScript面向对象特性的模拟
1. 继承的模拟
// 定义一个叫Person的类
function Person() {
this.show = function() {
alert("person");
}
}
var p = new Person();
p.show();
// 定义了一个Student的类
function Student() {}
// 模拟类的继承
Student.prototype = p;
var s = new Student();
s.show(); // 运行了父类的show方法
2. 重写的模拟
// 定义一个叫Person的类
function Person() {
this.show = function() {
alert("person");
}
}
var p = new Person();
p.show();
// 定义了一个Student的类
function Student() {
this.show = function() {
alert("Student");
}
}
// 模拟类的继承
Student.prototype = p;
var s = new Student();
s.show(); // 运行了子类的show方法
3. 重载的模拟
function add1(x, y) {
return x + y;
}
function add2(x, y, z) {
return x + y + z;
}
// 模拟重载
function add(x, y, z) {
// arguments为参数列表
if (arguments.length == 2) {
return add1(x, y);
} else if (arguments.length == 3) {
return add2(x, y, z);
}
}
alert(add(1, 2));
JavaScript的with语句和增强for循环
1. with(不推荐)
定义
with 语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性。要给对象创建新的属性,必须明确地引用该对象。
with(object instance)
{
//代码块
}
原先调用时:
var str = objInstance.a.b.c.属性;
这样调用时:
with(objInstance.a.b.c)
{
var str = 属性;
.....
}
去除了多次写对象名的麻烦。
示例
function Lakers() {
this.name = "kobe bryant";
this.age = "28";
this.gender = "boy";
}
var people = new Lakers();
with(people) {
var str = "姓名: " + name + "<br>";
str += "年龄:" + age + "<br>";
str += "性别:" + gender;
document.write(str);
}
问题
var root = {
branch: {
node: 1
}
};
with(root.branch) {
root.branch = {
node: 0
};
// 显示 1, 错误!
alert(node);
}
// 显示 0, 正确!
alert(root.branch.node);
with 语句内部的节点父节点修改后,不会同步到节点本身。也就是说,不能保证内外数值的一致性。这是可能成为项目里面隐藏性很高的 bug。所以可以使用别名引用父节点的方式来调用节点对象,而
不推荐使用with语句,如:
var root = {
branch: {
node: 1
}
};
var quote = root.branch;
quote.node = 0;
// 显示 0, 正确!
alert(root.branch.node);
2. 增强for
类似Java,可以使用关键字in来遍历数组:
var arr = ["北京", "上海", "广州"];
for (var i in arr) {
alert(i);
//输出的是索引:0 1 2
}
案例
城市级联
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>城市级联</title>
<script type="text/javascript" src="js.js"></script>
</head>
<body onload="_initProvince()">
<select id="province" onchange="_changeCity()">
<option>--请选择省份--</option>
</select>
<select id="city">
<option>--请选择城市--</option>
</select>
</body>
</html>
JavaScript:
var cityList = new Array();
cityList['北京市'] = ['朝阳区', '东城区', '西城区', '海淀区', '宣武区', '丰台区', '怀柔', '延庆', '房山'];
cityList['上海市'] = ['宝山区', '长宁区', '奉贤区', '虹口区', '黄浦区', '青浦区', '南汇区', '徐汇区', '卢湾区'];
cityList['广州省'] = ['广州市', '惠州市', '汕头市', '珠海市', '佛山市', '中山市', '东莞市'];
cityList['深圳市'] = ['福田区', '罗湖区', '盐田区', '宝安区', '龙岗区', '南山区', '深圳周边'];
function _initProvince() {
var provObj = document.getElementById("province");
// 加强for循环
for (var i in cityList) {
// i为列表索引号:北京市,上海市,广州市,深圳市
provObj.add(new Option(i, i));
}
}
function _changeCity() {
// 获取被选中的省份
var provObj = document.getElementById("province"); // 获取的是province对象
var optIdx = provObj.selectedIndex; // 获取选中的选项的下标
var optNode = provObj.options[optIdx]; // 根据下标找到选中的option对象
// 获取对应省份下的城市数组
var cityArr = cityList[optNode.value];
// 获取city下拉列表的对象
var cityObj = document.getElementById("city");
// 每次触发选择改变事件时,需将下拉列表的长度置为1
cityObj.length = 1;
// 遍历城市数组,将每个元素添加到city下拉列表中
for (var i = 0; i < cityArr.length; i++) {
cityObj.add(new Option(cityArr[i], cityArr[i]));
}
}
JSON
1. 定义
JSON:JavaScript 对象表示法(JavaScript Object Notation)。
JSON 是存储和交换文本信息的语法。类似 XML。
JSON 比 XML 更小、更快,更易解析。
2. 特点
- JSON 是轻量级的文本数据交换格式。
- JSON 独立于语言,JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。
- JSON 具有自我描述性,更易理解。
3. JSON与XML的异同
JSON 与 XML 共同点
- JSON 是纯文本
- JSON 具有“自我描述性”(人类可读)
- JSON 具有层级结构(值中存在值)
- JSON 可通过 JavaScript 进行解析
- JSON 数据可使用 AJAX 进行传输
JSON 与 XML 的区别
- 没有结束标签
- 更短
- 读写的速度更快
- 能够使用内建的 JavaScript eval() 方法进行解析
- 使用数组
- 不使用保留字
4. JSON与JavaScript对象的转换
JSON 文本格式在语法上与创建 JavaScript 对象的代码相同。
由于这种相似性,无需解析器,JavaScript 程序能够使用内建的 eval() 函数,用 JSON 数据来生成原生的 JavaScript 对象。
5. JSON语法规则
- 数据在名称/值对中。
- 数据由逗号分隔。
- 花括号保存对象。
- 方括号保存数组。
- JSON数据格式:"name" : "value",等效于JavaScript语句:name = "value";
示例
{
属性名 : 属性值,
属性名 : 属性值,
方法名 : function(){
方法体
//如果想访问json数据格式里面的属性,加上this
}
}
[
{属性名:属性值,属性名:属性值},
{属性名:属性值,属性名:属性值},
{属性名:属性值,属性名:属性值}
]
JSON的取值范围:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true 或 false)
- 数组(在方括号中)
- 对象(在花括号中)
- null
JSON数组:
{
"employees": [{
"firstName": "John",
"lastName": "Doe"
}, {
"firstName": "Anna",
"lastName": "Smith"
}, {
"firstName": "Peter",
"lastName": "Jones"
}]
}
换成JavaScript语法为:
var employees = [{
"firstName": "John",
"lastName": "Doe"
}, {
"firstName": "Anna",
"lastName": "Smith"
}, {
"firstName": "Peter",
"lastName": "Jones"
}];
6. JSON数据转换为JavaScript对象
直接使用var text = JSON数据即可。
示例
var text = {
"employees": [{
"firstName": "John",
"lastName": "Doe"
}, {
"firstName": "Anna",
"lastName": "Smith"
}, {
"firstName": "Peter",
"lastName": "Jones"
}]
}
alert(text.employees[0].firstName); // John