js中比较难捉摸透的大概就数this了,在php的面向对象编程中类里面的this就是指当前类,并不会变幻指向,但是js中的this却不同,稍不留神就会发现this的指向已经在不经意间就变了。但是区别是区别,和php的类一样的是js类中的this也只是出现在类中。
<script type="text/javascript">
/********** 案例一 ***********/
var v = 'ok';
function show() {
alert( this == window ); //true
alert( this.v );
}
show(); //ok
alert( window.v ); //ok
/********** 案例二 ***********/
function Person(name) {
this.name = name;
alert( this.name ); //koma
}
var p = new Person('koma');
alert( p.name ); //koma
/********** 案例三 ***********/
function Class(name) {
alert(this.v); //ok
function class_(name) {
this.name = name;
alert( this.name ); //koma
}
return new class_(name);
}
var c = Class('koma');
alert( c.name ); //koma
</script>
仔细看过上面的案例之后,其中可能最疑惑的就是案例一和三,因为二的话大家都在这么用,但是基本没有人去想过说这为什么this指向p,这里其实就和new操作符相关了,所以这里先不讨论,我们先讨论一和三。
其实对于js中的this可以用一句话来很好的定位this的指向,就是:谁调用this所在的函数,那么this就指向谁。
例如案例一,因为直接调用show()函数和window.show()的方式是一样的,那么其实就相当于是window在调用show函数,那么自然this就指向了window,然后变量v又是全局变量所以通过window.v可以访问,那么当调用show函数的时候,函数中this又指向window所以在函数中调用this.v其实就是相当于调用window.v,所以才会打印出ok这个结果。
对于案例三就有些绕了,但是当我们真正的剖析出本质的时候其实发现跟案例二其实是一样的。
当调用外层的Class的时候其实在Class的内部中的this是指向window的,但是我们又没有用到Class中的this所以它没有什么影响,那Class函数返回了内部函数class_的实例,那是不是可以看成是如下的方式:
function Class() {
function class_(name) {
this.name = name;
alert( this.name ); //koma
}
return class_;
}
var c_ = Class();
var c = new c_('koma');
alert( c.name ); //koma
首先调用Class函数的时候返回的仅仅是内部函数class_的名称,然后赋值给c_,这时呢c_就相当于函数class_,那么再实例化c_('koma')的时候就跟最开始的调用方式一样的,这时这个例子就和案例二一样了,所以此时的this是指向c的。
因为我们都知道,当new一个函数的时候,函数内部的this是指向new操作符返回的实例对象的,像案例二中this是指向p的,那么为什么this会指向p呢?当new的时候到底发生了什么呢?下面我们就来看看案例二。
var p = {};
p.__proto__ = Person.prototype;
Person.call(p, args);
return p;
那案例二整个的一个过程在内部分解出来之后就可以看作是由上面的四步构成的。
1,准备一个空对象p
2,让对象p的内置对象(__proto__)指向构造函数Person的原型
3,调用构造函数Person同时改变this的指向,使其指向this,初始化成员属性和方法等
4,返回对象p
其中第二步现在是可以忽略的,因为这部分涉及到了js中原型继承,这里也不讨论。
其中我们需要讨论的问题为什么案例二中我们认为函数Person中this是指向p的,那么在上面的第三步就可以解释的清楚了。
因为通过call来调用Person函数的时候动态的改变了this的指向,使得Person函数中this指向对象p,然后执行完成之后又把p返回,这样当执行:
var p = new Person() 的时候在Person函数内部this是指向p的。
那通过上面的整个分析之后,可以了解到js中关于this的一些情况同时呢又对js中new操作符有了一些了解,那到底new做了些什么呢,我们也都可以明确了,这对于后面的js面向对象编程的学习又是一大进步。
那上面还可能产生出一个问题就是call,那关于call的话只需要谷歌一下就可以了,这里不再说明。
接下来就简单的描述一下js中的闭包吧!
其实js中的闭包远没有好多人传说的那么难,那么晦涩,其实很简单的一句话就可以概括,什么叫闭包呢?说白了就函数里面再嵌套一个函数。那闭包有什么做用呢?说白了就是让一些变量常驻内存。什么叫常驻内存呢?假如说如下一个函数:
<script type="text/javascript">
function A() {
var x = 10;
alert(x);
}
A();
</script>
当程序执行完成A之后,那变量x就被回收了,再也找不到了。但是当换成如下的方式的时候:
<script type="text/javascript">
function A() {
var x = 10;
function B(x) {
alert(x);
}
B(x);
}
A();
</script>
当调用完成A函数之后变量x依然存在,因为它必须还要提供给B函数调用,这样就使得x留在了内存中,不立即的销毁。那这种方式有什么作用呢?简单的例子就是对于一个列表ul,假如它下面有三个li,当我们点击每个li的时候需要知道当前点击li的索引,这个怎么做呢?当然方法很多,但是用闭包实现的话就简单的多了,如下:
<ul id="ul1">
<li>111111111111</li>
<li>222222222222</li>
<li>333333333333</li>
</ul>
<script type="text/javascript">
var oLi = document.getElementById('ul1').getElementsByTagName('li');
for ( var i = 0; i < oLi.length; i++ ) {
(function(i) {
oLi.item(i).onclick = function() {
alert(i);
}
})(i);
}
</script>
这个就是闭包的一个简单使用了,当你理解了它之后那很多场合下使用闭包会简化操作,这里也不讨论多少,因为我自己也是处于学习期间,但是它真的没有传说的那么难懂,只需要分析一下就可以了。
通过这几篇文章的铺垫,下面呢就可以正式的开始js的面向对象编程的学习了,O(∩_∩)O哈!期待一下吧!