javascript 是一个基于对象的语言。 1 如果单单从对象的角度审视 js 的话,她是那么优雅,所有的都是对象,对象就是一个 key-value 集合,对象是动态的,可以动态地增加属性和方法。 2 虽然,每个 js 对象都有一个隐含的到其原型的链接(这个连接是隐藏的,firefox 上可以利用proto看到,对象字面量的原型是 Object.prototype),每个 js 对象都会继承其原型的属性,虽然 javascript 的对象与基于类的语言完全不同,但仍然是很优雅的,不就是一个每个对象有一个原型吗(一直到最顶端)。 。。。。。
虽然理论上是这样的,但 js 代码中我们不能直接操作这个原型链,即不能 obj2=obj1.proto,如果可以这样的话,确实是够优雅的,但 js 没有这样做,这是 js 的第一个坑,我们称之为proto坑。请参考 java good parts 一书,作者描述为:插入了一个多余的中间层
3 js 不仅有对象,还有函数 function,除了函数之外居然还有一个 new,一个没有 class 的世界居然有 new,你让大伙怎么想? 接下来我们先看函数,再看 new。 函数初看很简单,就像 c 语言中的方法,由函数名、参数、函数体组成,主要起到封装、重用代码的作用, 但是,js 中的函数可不简单(如果是这么简单就 ok 了)。
函数也是对象,什么,函数也是对象?在 c 系语言中可不是这样的,函数(方法)是函数(方法),对象是对象,怎么函数也是对象呢? 函数确实是对象,是一种特殊的对象,我们知道,js 中每个对象都是一个键值对集合,还包含一个到其原型的链接,那么函数对象呢?函数对象的原型是 Function.prototype(Function.prototype 本身会连接到 Object.prototype),此外,函数对象还有两个特殊的隐藏的属性:函数的上下文和执行函数的代码。
每个函数有一个 prototype 属性(特别注意,这是函数对象特有的属性,不要和 js 中每个对象到其原型的连接相混淆,那个玩意是隐藏的,不过在 firefox 中你可以使用proto访问到),这个 prototype 属性是一个对象,姑且称之为 prototypeObject 吧,这个对象有个 constuctor 属性,指向函数本身,绕了一圈。
既然函数是对象,那么这个特殊的对象也可以像其他普通的对象那样,可以有属性、有方法,可以被当做参数在函数中传递,。。 这个对象的特殊之处就是"可以被调用"(注意,我在这里加上了括号),可以被调用的含义,就是遇到这类对象你可以直接在对象后面加上一对括号,以及若干参数。(非可调用对象可没有这样的特权)
回到proto坑上,我们不能直接指定一个对象的原型链,这样的话,怎么实现继承呢(你 javascript 说了,我可以直接实现基于对象的继承,又不提供手段,我怎么实现这个继承呢)?js 提供了一个足够绕 的途径,通过构造函数,也就是通过函数来实现继承,当你 new 一个函数时,这个 new 出来的对象的原型指向函数的 prototype 属性(我们说过,这个属性是一个对象),这样下来确实是够绕的了。
为什么这样做呢,不是直接操作原型链而是通过一个函数的方式呢?有人(不用说你也知道此人谁了吧)说,js 的发明者对基于原型的继承不太自信,硬生生地搞了个传统面向对象语言中的对象创建方式的模仿品,结果有点成了四不像!!
再论 this: 在 java 中,也有个 new,这个 new 是和类 class 搭配的,一起合作,创建一个以类为模板的新的对象,
混乱开始:但是 js 中的这个 new 干嘛用的?和谁搭配用
在 js 中,函数可以这样用(作为构造函数),即 new 一个函数。
怪就怪在 new 这个操作,new 的操作实际分两步: 1 创建一个空的对象 2 将新创建的空对象作为 this,调用该函数。
function DogConstructor(name) {
this.name = name;
this.respondTo = function(name) {
if(this.name == name) {
alert("Woof");
}
};
}
var spot = new DogConstructor("Spot");
spot.respondTo("Rover"); // nope
spot.respondTo("Spot"); // yeah!</div>
上面的代码实际上就是:
// create an empty object
var spot = {};
// call the function as a method of the empty object
DogConstructor.call(spot, "Spot");
同时注意,函数里边有个 this,这个 this 是太动态了,this 指向的就是那个空的对象,这样的话,我们可以通过这种灵活性,可以以函数为模板,创建任意对象。
最后补充一点,js 设计成这样,我等平庸之辈只能瞻仰的份,对于 c 系程序员来说,这种语言的思维方式需要细细体会,(想想看,java 人渴望的一个 lamda 表达式历经多年还是那么难产),我们需要足够虔诚的态度拥抱这种迥异的语言。
另外,我想说的是,js 的动态性(她甚至可以修改 this)与函数性以及对象性是相辅相成,三者可以说缺一不可,再想想看,如果不能动态设置 this,函数作为一等公民是不可想象的。
欢迎大家吐槽!