zoukankan      html  css  js  c++  java
  • JavaScript 的 OOP 功能解析

    根据JavaScript创始人Brandon Eich 自己的说法,JavaScript 最好的语言构造是:

    1. 函数是一等公民 (first class functions)
    2. 闭包 (closure) 
    3. Prototypes
    4. Obj = {p1: 1, P2: ‘abc’}
    5. Array = [1,2,3]

    我认为,JS最精彩的思想是突破了当时OOP的局限性,把object而不是class变成了一等公民(Eich 的1,4,5三条都是这一思想的展现)。

    C++,Java,C#等语言其实是class-oriented,强调type,没有作为个体的object的支持,只有“共性”而没有“个性”。JavaScript作为一“动态语言”,理所当然地支持动态地创建object,支持动态地修改object.

    下面是我对Eich的补充:

    JavaScript object 是一等公民,函数是object的super-set

    函数是一个平常的object,它有属性(property),也可以有“member function”,下面的code可以证明这一点:

    function foo(x, y)

    {

                   if (foo.xyz  === undefined)  {

                        foo.xyz = 0;

                    }

                    else {

                                  foo.xyz  += x + y;

                   }

                   console.log('foo.xyz:' + foo.xyz);

    }

     

    foo(1, 2);   // 0

    foo(1, 2);   // 3

    foo(1, 2);   // 6

     

    上面函数foo定义了property xyz,和一般的object并无异处。

    函数也可以有“member function”,下面的code可以证明这一点:

    function foo(x, y)

    {

                   var z = (x + y);

                   console.log('x + y = ' + z);

    }

    foo.bar = function() { console.log('Hello, I am bar.') };

     

    foo(1, 2);  // x + y = 3

    foo.bar(); // Hello, I am bar.

     

    但是非函数的object却不能当作函数用, 下面code不会工作:

    var obj = {p1: 100};

    obj();

     

    结论是:函数是普通的object,并非特殊公民,它无非是 加上个()operator。而 () operator 是个内含“可执行的字符串(executable literal)” 的属性。

    JavaScript对class概念的支持

     

    上面说了,JavaScript真正地把object的地位提高到一等,扩展和丰富了我们对OOP的认识。

    然而class对于任何一个严肃的OOP工程,仍然是不可缺少,甚至是至关重要的。这就是Eich的第三条:prototype的重要性了。我在咨询过程中,屡屡帮助不喜欢用class的项目合理使用class和class inheritance,大大减少重复代码,提高了程序的抽象性和可维护性。

    JavaScript没有class。微软的TypeScript加了class,interface,和inheritance的支持,都是通过函数和prototype实现的。Prototype ,和一等公民的object一起,是实现class的金钥匙。

    那么什么是prototype呢,其实它无非是一个函数object的named (命名的)属性罢了。只是这个属性是语言本身附加的,不是编程加上的。它是函数的“共性”,而我们知道class正是object的共性。

    我们下面举个例子,看看如何用函数(这里特别称作constructor),和prototype来模拟class

    function MyClass(x, y)

    {

                   this.prop1 = x;

                   this.prop2 = y;

    }

    MyClass.prototype.getProp1 = function () { console.log('this.prop1:' + this.prop1);}

     

    var obj = {};                                            // line1: manually create an object

    MyClass.call(obj, 10, 20);                           // line2: call constructor manually on obj1

    obj.constructor = MyClass;                       // line3: set MyClass as obj's constructor manually

    callMemberFunc(obj, 'getProp1');              // line4: 10 (simulating member function call

     

    var obj2 = {};                                         // line5: manually create another object

    MyClass.call(obj2, 30, 40);                        // line6: call constructor manually on obj2

    obj2.constructor = MyClass;                      // line7: set MyClass as obj's constructor manually

    callMemberFunc(obj2, 'getProp1');             // line8: 30 (simulating member function call

     

    JavaScript的每个函数都有一个prototype属性。其实,这只是方便而已,自己创建一个属性也一样。这个属性的目的是给所有用这个函数的object一个类似于c++ vtble的表格,来添加属性和函数。那么,如何将object和这个prototype挂钩呢?JavaScript给每一位要成为class 中一员的object一个新的属性:constructor。Constructor作为一个ID,来辨识一个特定的class,而这个constructor,当然非负责初始化的函数莫属了!

    这一切都可以用JavaScript提供的现有语言构造来手动实现。上面的例子就说明了这一点。

    我们的目标是创建MyClassinstancesobjobj2MyClass 是一个“构造函数”,更确切地说是“初始化函数”。

    我们首先手动创建obj (line1),然后call MyClass (line2)来初始化这个新的object, 再把obj 的constructor属性设为MyClass (line3),这样就把obj和MyClassprototype联系上了。

    我们用同样的手段创建了obj2 (line5 ~ line7)。

    这两个object 是否属于同一个class呢?是的,有下面两个证明:

    A) obj.constructor == obj2.constructor 成立,证明他们同属一个构造函数,即同属一类。

    B) callMemberFunc 可以call 任何以MyClass.prototype的函数(line4line8

    那么什么是callMemberFunc,它有普遍性吗?答案是肯定的,下面是我的callMemberFunc定义,可以用来call任何函数(需要增强些功能罢了,比如函数参数处理)。

    // call a member function for an object

    function callMemberFunc(obj, name) {

                   if (obj[name] !== undefined) {

                                  //console.log('getProp ' + 'found ' + name + ' value:');

                                  return obj[name].call(obj);

                   }

                   if (obj.constructor !== undefined) {

                                  //console.log('getProp ' + 'found ' + name + ' in constructor.prototype, value:');

                                  return obj.constructor.prototype[name].call(obj);

                   }

    }

    总之,JavaScript通过简单的构造,即可以实现class-oriented程序设计,使得OOP的class功能可以实现。我这里只是部分的实现,但是和JavaScript编译生成的代码,基本功能一致。

    JavaScript的syntax sugar,也使得实现上述思想易如反掌:

    var obj3 = new MyClass(40, 50);         // line9: use 'new' operator

    obj3.getProp1();                                 // line10: 40

    JavaScript 的new operator (line9),取代了我上面的手动代码(line1 ~ line3), 而callMemberFunc更是被一个简单的“直接调用”(line10)所取代。 

    总结

    JavaScript程序设计是OOP的全新体验和扩展,将object真正提到了崇高地位,也是在OOP的基础上,将FP (functional programming) 和OOP的一次大统一。

    2014-9-1 于西雅图

  • 相关阅读:
    Luogu3118:[USACO15JAN]Moovie Mooving
    Luogu4137:Rmq Problem/mex
    Luogu3092:[USACO13NOV]No Change
    BZOJ4321: queue2
    BZOJ4650 : [NOI2016]优秀的拆分
    webpack
    sublime eslint setup
    Sublime themes/ lint themes setup
    sublime text 3
    React
  • 原文地址:https://www.cnblogs.com/ly8838/p/3951444.html
Copyright © 2011-2022 走看看