查看对象属性配置
如果查看并管理对象的这些配置,下面有个程序可以输出对象的属性和配置等东西:
 
复制代码 代码示例:
//列出对象的属性.    
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>');