计划按如下顺序完成这篇笔记:
- 理念。
- 属性复制和继承。
- this/call/apply。
- 闭包/getter/setter。
- prototype。
- 面向对象模拟。
- jQuery基本机制。
- jQuery选择器。
- jQuery工具方法。
- jQuery-在“类”层面扩展。
- jQuery-在“对象”层面扩展。
- jQuery-扩展选择器。
- jQuery UI。
- 扩展jQuery UI。
这是笔记的第3篇,聊聊JavaScript中的this,还有两种调用函数的特殊方式:call 和 apply。
this
JavaScript中的this和Java中的this区别较大。学过Java的童鞋请忘掉你知道的关于this的一切。
JavaScript中的this是依赖于函数的,表示函数的调用者。有两个意思:第一,this不是函数本身;第二,函数被调用的时候才决定this指向谁。
分以下几种情况:
调用全局函数
看下面的代码:
<span style="background-color: rgb(255, 255, 153);"><span style="color:#FF0000;"><strong>代码段1:</strong></span></span> function UiObject(){ console.log(this.name || this.toString()); // 输出:[object Window] console.log(this===window); // 输出:true } UiObject()
默认为window调用,this为window。
通过对象调用
<span style="background-color: rgb(255, 255, 153);"><span style="color:#FF0000;"><strong>代码段2:</strong></span></span> function UiObject(){ this.render = function(str){ console.log('render this ',str,' by ' + this.toString()); console.log(this === UiObject); // false <strong>console.log(this === ui); // true</strong> } } var ui = new UiObject(); ui.render();
如果函数在原型中定义呢?
<span style="background-color: rgb(255, 255, 153);"><span style="color:#FF0000;"><strong>代码段3:</strong></span></span> function UiObject(){} UiObject.prototype = { render : function(str){ console.log('render this ',str,' by ' + this.toString()); console.log(this === UiObject); // false <strong>console.log(this === ui); // true</strong> ,结果一样,谁调用,this指向谁 } }; var ui = new UiObject(); ui.render();
结果一样,在哪儿定义不重要,被谁调用才重要。有奶的就是娘,谁生的不重要,好现实...
再写段代码让这个特性更明显,如下:
<span style="background-color: rgb(255, 255, 153);"><span style="color:#FF0000;"><strong>代码段4:</strong></span></span> function hunt(){ console.log('To ',this.name + ', my dear lord! I will hunt ',this.target,' as your wish.'); console.log(this === hailong); console.log(this === haichao); } var hailong = { name : 'Lord Hailong', target : 'deer' }; var haichao = { name : 'Lord Haichao', target : ' Little-Japs ' }; hailong.hunt = hunt; // 输出:To Lord Hailong, my dear lord! I will hunt deer as your wish. // 输出:true -- console.log(this === hailong); // 输出:false -- console.log(this === haichao); hailong.hunt(); haichao.kill = hunt; // 输出:To Lord Haichao, my dear lord! I will hunt Little-Japs as your wish. // 输出:false -- console.log(this === hailong); // 输出:true -- console.log(this === haichao); haichao.kill();
有奶就是娘,谁调用,this就指向谁。
被事件调用
被事件调用分几种情况:
1、<div
onclick=‘theFunc()‘>
2、oDiv.onclick
= theFunc ;
第1中情况,this指向window,第2中情况,this指向oDiv。
arguments
和this类似,函数被调用时,argmuments将被赋值为传入的传入的参数数组。
可以通过 arguments.length获得传入参数的个数,可以通过arguments[idx]获得传入参数的值。
基于this的特性,我们需要特殊的方法灵活控制this的指向。
JavaScript为我们提供了call和apply两个方法。
call
在函数调用的时候,通过call方法,可以指定调用者,从而实现了对this的灵活绑定。语法如下:
func.call(invokerObject);
func是函数,invokerObject将被指定为函数的调用者。看下面的例子。
<pre name="code" class="javascript"><span style="background-color: rgb(255, 255, 153);"><span style="color:#FF0000;"><strong>代码段5:</strong></span></span>
function hunt(){}var hailong = {name : ‘Lord Hailong‘,target : ‘deer‘};var haichao = {name : ‘Lord Haichao‘,target : ‘ Little-Japs ‘};function printName(){console.log(‘Name:‘,this.name);}printName.call(hunt);printName.call(hailong);printName.call(haichao);
定义好printName方法后,希望能应用到hunt、hailong、haichao几个对象上。通过call函数即可实现。printName函数中的this成功指向了通过call参数传入的对象。
printName.call(hailong)
等同于下面的语句:
hailong.printName = printName;
hailong.printName();
delete haiong.printName;
apply
通过call方法调用函数,如果有参数,从call方法的第二个参数开始传入。语法如下:
function func(p1,p2,p3){}
func.call(targetObject,p1,p2,p3)
apply方法与call方法实现相同的功能,不同的是,当传入参数时,所有的参数组成一个数组,作为apply的第二个参数传入,语法如下:
func.apply(targetObject,[p1,p2,p3])
同arguments结合使用时,apply方法更方便。
小结
- 搞清楚this的含义,是基础中的基础。
- 通过call、apply可以灵活绑定this的值。