zoukankan      html  css  js  c++  java
  • Javascript 面向对象编程

    Javascript是一个类C的语言,他的面向对象的东西相对于C++/Java比较奇怪,但是其的确相当的强大。

    在 Todd 同学的“对象的消息模型”一文中我们已经可以看到一些端倪了。

    这两天有个前同事总在问我Javascript面向对象的东西,所以,索性写篇文章让他看去吧,

    这里这篇文章主要想从一个整体的角度来说明一下Javascript的面向对象的编程。(成文比较仓促,应该有不准确或是有误的地方,请大家批评指正)

    另,这篇文章主要基于 ECMAScript 5, 旨在介绍新技术。关于兼容性的东西,请看最后一节。

    初探

    我们知道Javascript中的变量定义基本如下:

    var name = 'Chen Hao';
    var email = 'haoel(@)hotmail.com';
    var website = 'http://coolshell.cn';

    如果要用对象来写的话,就是下面这个样子:

    var chenhao = {
        name :'Chen Hao',
        email : 'haoel(@)hotmail.com',
        website : 'http://coolshell.cn'
    };

    于是,我就可以这样访问:

    //以成员的方式
    chenhao.name;
    chenhao.email;
    chenhao.website;
    
    //以hash map的方式
    chenhao["name"];
    chenhao["email"];
    chenhao["website"];

    关于函数,我们知道Javascript的函数是这样的:

    var doSomething = function(){
        alert('Hello World.');
    };

    于是,我们可以这么干:

    var sayHello = function(){
        var hello = "Hello, I'm "+ this.name + ",
                               my email is: " + this.email + ",
                               my website is: " + this.website;
        alert(hello);
    };
    //直接赋值,这里很像C/C++的函数指针
    chenhao.Hello = sayHello;
    chenhao.Hello();

    相信这些东西都比较简单,大家都明白了。

    可以看到javascript对象函数是直接声明,直接赋值,直接就用了。

    runtime的动态语言。还有一种比较规范的写法是:

    //我们可以看到,其用function来做class。
    var Person = function(name, email, website)
    {
        this.name = name;
        this.email = email;
        this.website = website;
        this.sayHello = function()
        {
            var hello = "Hello, I'm "+ this.name  + ", \n" +
                                   "my email is: " + this.email + ", \n" +
                                 "my website is: " + this.website;
            alert(hello);
        };
    };
    var chenhao = new Person("Chen Hao", "haoel@hotmail.com",
                                          "http://coolshell.cn");
    chenhao.sayHello();

    顺便说一下,要删除对象的属性,很简单:

    delete chenhao['email']

    上面的这些例子,我们可以看到这样几点:

    ①Javascript的数据和成员封装很简单。没有类完全是对象操作。纯动态!

    ②Javascript function中的this指针很关键,如果没有的话,那就是局部变量或局部函数。

    ③Javascript对象成员函数可以在使用时临时声明,并把一个全局函数直接赋过去就好了。

    ④Javascript的成员函数可以在实例上进行修改,也就是说不同实例相同函数名的行为不一定一样。

    属性配置 – Object.defineProperty

    先看下面的代码:

    //创建对象
    var chenhao = Object.create(null);
    
    //设置一个属性
    Object.defineProperty( chenhao,
                           'name', { value:  'Chen Hao',
                                     writable:     true,
                                     configurable: true,
                                     enumerable:   true
                                    });
    
    //设置多个属性
    Object.defineProperties( chenhao,
        {
            'email'  : { value:  'haoel@hotmail.com',
                         writable:     true,
                         configurable: true,
                         enumerable:   true },
            'website': { value: 'http://coolshell.cn',
                         writable:     true,
                         configurable: true,
                         enumerable:   true }
        }
    );

    下面就说说这些属性配置是什么意思。

    writable:这个属性的值是否可以改。

    configurable:这个属性的配置是否可以改。

    enumerable:这个属性是否能在for…in循环中遍历出来或在Object.keys中列举出来。

    value:属性值。

    get()/set(_value):get和set访问器。

    Get/Set 访问器

    关于get/set访问器,它的意思就是用get/set来取代value(其不能和value一起使用),示例如下:

    var  age = 0;
    Object.defineProperty( chenhao,
                             'age', {
                                         get: function() {return age+1;},
                                        set: function(value) {age = value;}
                                        enumerable : true,
                                        configurable : true
                                    } );
    chenhao.age = 100; //调用set
    alert(chenhao.age); //调用get 输出101(get中+1了);

    我们再看一个更为实用的例子——利用已有的属性(age)通过get和set构造新的属性(birth_year):

    Object.defineProperty( chenhao,
                      'birth_year',
                      {
                              get: function() {
                                 var d = new Date();
                                 var y = d.getFullYear();
                                 return ( y - this.age );
                            },
                            set: function(year) {
                                 var d = new Date();
                                 var y = d.getFullYear();
                                 this.age = y - year;
                            }
                        }
    );
    alert(chenhao.birth_year);
    chenhao.birth_year = 2000;
    alert(chenhao.age);

    这样做好像有点麻烦,你说,我为什么不写成下面这个样子:

    var chenhao = {
         name: "Chen Hao",
         email: "haoel@hotmail.com",
         website: "http://coolshell.cn",
         age: 100,
         get birth_year() {
              var d = new Date();
             var y = d.getFullYear();
             return ( y - this.age );
             },
         set birth_year(year) {
              var d = new Date();
             var y = d.getFullYear();
             this.age = y - year;
             }
    };
    alert(chenhao.birth_year);
    chenhao.birth_year = 2000;
    alert(chenhao.age);

    是的,你的确可以这样的,不过通过defineProperty()你可以干这些事:

    ①设置如 writable,configurable,enumerable 等这类的属性配置。

    ②动态地为一个对象加属性。比如:一些HTML的DOM对像。

    查看对象属性配置

    如果查看并管理对象的这些配置,下面有个程序可以输出对象的属性和配置等东西:

    //列出对象的属性.
    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。

    http://coolshell.cn/articles/6441.html

  • 相关阅读:
    将博客搬至CSDN
    python第三方库安装技巧
    windows下如何安装pip以及如何查看pip是否已经安装成功?
    API测试基础
    成功实施自动化测试的优点
    自动化如何选择用例
    Selenium 4.0 Alpha更新实践
    Selenium 4.0 Alpha更新日志
    Selenium 4 Python的最佳测试框架
    Gradle+Groovy提高篇
  • 原文地址:https://www.cnblogs.com/laonanren/p/2998156.html
Copyright © 2011-2022 走看看