查看对象属性配置
如果查看并管理对象的这些配置,下面有个程序可以输出对象的属性和配置等东西:
复制代码 代码示例:
//列出对象的属性.
function listProperties(obj)
{
var newLine = "<br />";
var names = Object.getOwnPropertyNames(obj);
for (var i = 0; i < names.length; i++) {
var prop = names[i];
document.write(prop + newLine);
// 列出对象的属性配置(descriptor)动用getOwnPropertyDescriptor函数。
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
for (var attr in descriptor) {
document.write("..." + attr + ': ' + descriptor[attr]);
document.write(newLine);
}
document.write(newLine);
}
}
listProperties(chenhao);
call,apply,bind和this
关于 Javascript 的 this 指针,和C++/Java 很类似。
来看个示例:
复制代码 代码示例:
function print(text){
document.write(this.value + ' - ' + text+ '<br>');
}
var a = {value: 10, print : print};
var b = {value: 20, print : print};
print('hello');// this => global, output "undefined - hello"
a.print('a');// this => a, output "10 - a"
b.print('b'); // this => b, output "20 - b"
a['print']('a'); // this => a, output "10 - a"
再来看看call和apply,这两个函数的差别就是参数的样子不一样,另一个就是性能不一样,apply 的性能要差很多。(关于性能,可到 JSPerf 上去跑跑看看)
复制代码 代码示例:
print.call(a, 'a'); // this => a, output "10 - a"
print.call(b, 'b'); // this => b, output "20 - b"
print.apply(a, ['a']); // this => a, output "10 - a"
print.apply(b, ['b']); // this => b, output "20 - b"
但是在 bind 后,this 指针,可能会有不一样,但是因为 Javascript 是动态的。如下面的示例
复制代码 代码示例:
var p = print.bind(a);
p('a'); // this => a, output "10 - a"
p.call(b, 'b'); // this => a, output "10 - b"
p.apply(b, ['b']); // this => a, output "10 - b"
继承和重载
通过上面的那些示例,可以通过 Object.create ()来实际继承,请看下面的代码,Student 继承于 Object。
复制代码 代码示例:
var Person = Object.create(null);
Object.defineProperties
(
Person,
{
'name' : { value: 'Chen Hao'},
'email' : { value :
'haoel@hotmail.com'},
'website': { value: 'http://www.jb200.com'}
}
);
Person.sayHello = function () {
var hello = "<p>Hello, I am "+ this.name + ", <br>" +
"my email is: " + this.email + ", <br>" +
"my website is: " + this.website;
document.write(hello + "<br>");
}
var Student = Object.create(Person);
Student.no = "1234567"; //学号
Student.dept = "Computer Science"; //系
//使用Person的属性
document.write(Student.name + ' ' + Student.email + ' ' + Student.website +'<br>');
//使用Person的方法
Student.sayHello();
//重载SayHello方法
Student.sayHello = function (person) {
var hello = "<p>Hello, I am "+ this.name + ", <br>" +
"my email is: " + this.email + ", <br>" +
"my website is: " + this.website + ", <br>" +
"my student no is: " + this. no + ", <br>" +
"my departent is: " + this. dept;
document.write(hello + '<br>');
}
//再次调用
Student.sayHello();
//查看Student的属性(只有 no 、 dept 和 重载了的sayHello)
document.write('<p>' + Object.keys(Student) + '<br>');
通用上面这个示例,可以看到,Person 里的属性并没有被真正复制到了 Student 中来,但是可以去存取。这是因为 Javascript 用委托实现了这一机制。其实,这就是 Prototype,Person 是 Student 的 Prototype。
当代码需要一个属性时,Javascript 的引擎会先看当前的这个对象中是否有这个属性,如果没有的话,就会查找他的 Prototype 对象是否有这个属性,一直继续下去,直到找到或是直到没有 Prototype 对象。
为了证明这个事,可以使用 Object.getPrototypeOf ()来检验一下:
复制代码 代码示例:
Student.name = 'aaa';
//输出 aaa
document.write('<p>' + Student.name + '</p>');
//输出 Chen Hao
document.write('<p>' +Object.getPrototypeOf(Student).name + '</p>');
于是,还可以在子对象的函数里调用父对象的函数,就好像 C++ 里的 Base::func () 一样。
于是,重载 hello 的方法就可以使用父类的代码了,如下所示:
复制代码 代码示例:
//新版的重载SayHello方法
Student.sayHello = function (person) {
Object.getPrototypeOf(this).sayHello.call(this);
var hello = "my student no is: " + this. no + ", <br>" +
"my departent is: " + this. dept;
document.write(hello + '<br>');
}
组合
上面的那个东西还不能满足的要求,可能希望这些对象能真正的组合起来。为什么要组合?因为都知道是这是 OO 设计的最重要的东西。不过,这对于 Javascript 来并没有支持得特别好,不好依然可以搞定个事。
首先,需要定义一个 Composition 的函数:(target 是作用于是对象,source 是源对象),下面这个代码还是很简单的,就是把 source 里的属性一个一个拿出来然后定义到 target 中。
复制代码 代码示例:
function Composition(target, source)
{
var desc = Object.getOwnPropertyDescriptor;
var prop = Object.getOwnPropertyNames;
var def_prop = Object.defineProperty;
prop(source).forEach(
function(key) {
def_prop(target, key, desc(source, key))
}
)
return target;
}
有了这个函数以后,就可以这来玩了:
复制代码 代码示例:
//艺术家
var Artist = Object.create(null);
Artist.sing = function() {
return this.name + ' starts singing...';
}
Artist.paint = function() {
return this.name + ' starts painting...';
}
//运动员
var Sporter = Object.create(null);
Sporter.run = function() {
return this.name + ' starts running...';
}
Sporter.swim = function() {
return this.name + ' starts swimming...';
}
Composition(Person, Artist);
document.write(Person.sing() + '<br>');
document.write(Person.paint() + '<br>');
Composition(Person, Sporter);
document.write(Person.run() + '<br>');
document.write(Person.swim() + '<br>');
//看看 Person中有什么?(输出:sayHello,sing,paint,swim,run)
document.write('<p>' + Object.keys(Person) + '<br>');