魏名华

不要偷懒,做更好的自己

Nothing


No Welcome Message

重学前端-06 | JavaScript对象:面向对象还是基于对象?

在不同的编程语言中,设计者也利用各种不同的语言特性来抽象描述对象,最为成功的流派是使用“类”的方式来描述对象,这诞生了诸如 C++、Java 等流行的编程语言。

而 JavaScript 早年却选择了一个更为冷门的方式:原型(关于原型,我在下一篇文章会重点介绍,这里你留个印象就可以了)。这是我在前面说它不合群的原因之一。 
 
然而很不幸,因为一些公司政治原因,JavaScript 推出之时受管理层之命被要求模仿 Java,所以,JavaScript 创始人 Brendan Eich 在“原型运行时”的基础上引入了 new、this 等语言特性,使之“看起来更像 Java”。

JS 所使用的原型,是个什么样的存在啊?


如果我们从运行时角度来谈论对象,就是在讨论 JavaScript 实际运行中的模型,这是由于任何代码执行都必定绕不开运行时的对象模型。 

不过,幸运的是,从运行时的角度看,可以不必受到这些“基于类的设施”的困扰,这是因为任何语言运行时类的概念都是被弱化的。

在我看来,不论我们使用什么样的编程语言,我们都先应该去理解对象的本质特征(参考 Grandy Booch《面向对象分析与设计》)。

“任何语言运行时类的概念都是被弱化的。” 这倒是有意思了


我们先来看第一个特征,对象具有唯一标识性。一般而言,各种语言的对象唯一标识性都是用内存地址来体现的, 对象具有唯一标识的内存地址,所以具有唯一的标识。 

所以,JavaScript 程序员都知道,任何不同的 JavaScript 对象其实是互不相等的,我们可以看下面的代码,o1 和 o2 初看是两个一模一样的对象,但是打印出来的结果却是 false。

    var o1 = { a: 1 };
    var o2 = { a: 1 };
    console.log(o1 == o2); // false

这倒是,iOS里面会通过特殊的手段,去判断2个对象的内容是否是一样的,但本质上,内容一致不代表对象是相等的。


关于对象的第二个和第三个特征“状态和行为”,不同语言会使用不同的术语来抽象描述它们,比如 C++ 中称它们为“成员变量”和“成员函数”,Java 中则称它们为“属性”和“方法”。 

在 JavaScript 中,将状态和行为统一抽象为“属性”,考虑到 JavaScript 中将函数设计成一种特殊对象(关于这点,我会在后面的文章中详细讲解,此处先不用细究),所以 JavaScript 中的行为和状态都能用属性来抽象。

理解了函数式编程,这个倒是能理解,而且,也终于理解了下面这些 JS 代码


    /// es6 可这样
    var o = { 
        d: 1,
        f() {
            console.log(this.d);
        }    
    };

    /// 这个直接语法错误
    var o = { 
        d: 1,
        function f() {
            console.log(this.d);
        }    
    };

    /// 古老的写法
    var o = { 
        d: 1,
        f: function() {
            console.log(this.d);
        }    
    };


从运行时的角度,介绍了 JavaScript 对象的具体设计:具有高度动态性的属性集合。

现在能理解这句话了