今天周末,夜里没事再把JS梳理一下。有兴趣的可以静下来当成个故事慢慢看。
首先说的对象。比如 var o={}
创建一个对象o,但是我们没有看到构造函数。根据面向对象的思路,此处应该有个构造函数。比如C++的new 类型。
我们应该猜到,这是语法省略了。可经过这么省略,很多事情就变的迷惑了。事实上,完整的写法是:var o = new Object()
其中,Object()就是一个内置的构造函数。这一步非常关键,是下面一些理论的基础
在书上,我们常常看到原型(prototype)的说法,原型是函数才能拥有的,即原型是函数的原型。就像上面的Object(),它是一个函数,因此
它具有原型。但又因为它是内置的函数,因此赋予了很多方法。查看:Object.prototype。
Object.prototype
对象o因为通过Object()构造而来,因此它能引用Object的原型(prototype),在浏览器中可以通过o.__proto__来查看
因此,可以总结出下面一段话:
原型prototype是函数才具有的,表现形式为:函数.prototype
由此函数创建的对象可以引用原型,表现形式为:对象.__proto__,换句话说,对象要引用构造的原型,需要给它一个属性来引用,这个引用是__proto__
现在,我们再来看下函数,相对来说,它是JS中比较复杂的一种类型。但是在这里,我们首先也把它看成对象。原因是:在JS中一切皆对象。
比如:我们创建一个函数
function f(){}
如果在全局中创建,那么它就是浏览器全局对象window的一个属性。 window.f=function(){}
因为我们说函数f是一个对象,那么就问,它的构造函数是谁呢?这个问题如果不搜索一些资料还是很难理解
函数作为对象,必定也有一个构造函数,它的构造函数就是Object(),也就是,函数都是Object()的一个实例。但是它又会把自己的构造函数设置成自己。
这个问题可以通过浏览器查看验证。我们总结一句话:函数都是Object的实例,它的构造函数是自身。
因此,我们会看到f.__proto__指向的就是Object的prototype..
又因为,f.__proto__指向Object,因此通过此函数构造出来的对象就能引用Object的prototype,其实就是上面所说的原型链。我相信这些推导难不住聪明的程序员
下面通过一段对话对上面进行总结:
问:
function f(){}
var o = new f()
为什么o能引用Object的prototype?
=> 函数f也是对象,它的构造函数是Object(),因此f.__proto__指向Object.prototype
f.prototype={
construtor:f,
__proto__:Object.prototype
}
又因为对象o通过f构造而来,而此 o.__proto__=f.prototype,根据原型链往上引用查找,就可以引用到Object的prototype。
--------
下面,我们继续讨论函数
函数是可被任意调用的一段代码,内部可以使用this。任意调用是什么意思呢?就是说它没有自主权。就像一间房子,谁能出房租就租给谁占用。
funciton f(){ return this.name; }
看下这段代码,字面上看就是打印this.name。在面向对象中,this表示当前对象。
可以认为这是一段静止的代码(自由、无自主权、需要依赖某个对象),谁调用它,它就打印谁的name
为了方便,它有一个call和apply的方法,形式为:函数.call(对象,参数)。这样一看更容易明白,函数是自由的。比如:
var o = {}
o.name = "tianya"
f.call(o,null) //输出"tianya"
但是先等等,这个call从哪来的?
如果前面的原型链理解的话,我们知道,一个对象的方法,要么是它自已定义的,要么是从祖先"继承"过来的。那么函数f的这个call从哪来的呢?
前面说过,f的构造函数是指向自己,即 f.constructor=this,这个构造函数的__proto__指向的是原生f(斜体)的prototype。那么我们继续往下
问这个原生f又是怎么回事儿?
从哲学上来说,我们可以无限的往下追问,但是往往都会有一个尽头。就像windowsAPI,无论我们把它的使用了解的多么清楚,但是只能停留到API的
那一层,就是追问的尽头,底层实现再也没法查看。因此,我们可以说,这个斜体的原生f就是语言内置的。
因此从这可以说,一个函数(同时也是一个对象,这样说是有点挺绕的),可以从两个方向来继承,1. 从构造函数的方向继承祖先的一些方法 2. 直接
继承Object()。而call,apply等,正是从构造函数那个方向继承过来的。(注:这一段可以通过浏览器查看)
再回到正文,call和apply的出现,可以达成一些效果。就是一个方法明明是其它对象的,但也可以借来调用。到这里,我们可以看出,函数是自由的,
仿佛它不是本质归属于哪个对象。