本文共 3355 字,大约阅读时间需要 11 分钟。
第2章this、call和apply
跟别的语言大相径庭的是,javascript的this总是指向一个对象,而具体指向哪个对象是运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。
this的指向
除去不常用的with和eval的情况,具体到实际应用中,this的指向大致可以分为以下4种
o 作为对象的方法调用
o 作为普通函数调用
o 构造器调用
o Function.prototype.call或Function.prototype.apply调用。
1. 作为对象方法的调用
当作为对象方法调用时,this指向该对象:
- var obj = {
- a:1,
- getA:function(){
- alert(this==obj);
- alert(this.a);
- }
- }
- obj.getA();
2. 作为普通函数调用
当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的this总是指向全局对象。在浏览器js里,这个全局对象是window对象
如:
- window.name = ‘globalName’;
- var getName = function(e){
- return this.name;
- }
- console.log(getName());
或者
- window.name = ‘globalName’;
- var myObject = {
- name:’sven’,
- getName:function(){
- return this.name;
- }
- }
- var getName = myObject.getName;
- console.log(getName());
有时候我们会遇到一些困扰,比如在div节点的事件函数内部,有一个局部的callback方法,callback方法作为普通方法调用内部的this指向window,但我们往往是想让它指向div节点。
如下:
- <html>
- <body>
- <div id=”div1”>我是一个div</div>
- </body>
- <script>
- window.id = “window”;
- document.getElementById(“xxx”).onclick = function(){
- alert(this.id); //输出:div
- var callback = function(){
- alert(this.id); //输出:window
- };
- callback();
- }
-
- </script>
- </html>
此时有一种简单的解决方案,就是用一个变量保存div节点的引用
- document.getElementById(“xxx”).onclick = function(){
- var that = this;
- alert(this.id);
- var callback = function(){
- alert(that.id);
- };
- callback();
- }
在ECMAScript5的strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefined。
- function func(){
- “use strict”
- alert(this);
- }
3. 构造器调用
javascript中没有类,但是可以从构造器中创建对象,同是也提供了new运算符,使得构造器看起来更像一个类
除了宿主提供的一些内置函数,大部分javascript函数都可以当作构造器使用。构造器的外表跟普通函数一模一样,它们的区别在于被调用的方式。当用new运算符调用函数时该函数会返回一个对象。
- var MyClass = function(){
- this.name = ‘sven’;
- }
- var obj = new MyClass();
- alert(obj.name);
注意:如果new 调用构造器时还要注意一个问题,如果构造器显式地返回一个object类型的对象,那么此次运算结果最终会返回这个对象(参见之前的总结)
- var MyClass = function(){
- this.name = ‘sven’;
- return {
- name:’anne’
- }
- }
- var obj = new MyClass();
- alert(obj.name);
注意如果构造器不显式返回的不是一个对象类型的数据就不会造成上述问题。
如:
- var MyClass = function(){
- this.name = ‘sven’;
- return “question”;
- }
- var obj = new MyClass();
- alert(obj.name);
4. Functon.prototype.call或Function.prototype.apply调用
动态改变传入函数的this
2.1丢失this
如:
- var obj = {
- myName:”sven”,
- getName:function(){
- return this.myName;
- }
- }
- console.log(obj.getName());
- var getName2 = obj.getName;
- console.log(getName2());
-
- var getId = function(id){
- return document.getElementById(id);
- }
而不是简单的这样
var getId = document.getElementById; //普通函数调用啦,上下文指向的不是document而是window对象啦
call和apply的区别就是前者的参数对应传递是单个的,后者以数组的形式传递函数的参数。
借用其他对象的方法
借用方法的第一种场景就是借用构造函数,通过这种技术,可以以实现类似继承的效果:
- var A = function(name){
- this.name = name;
- }
-
- var B = function(){
- A.apply(this,arguments);
- }
- B.prototype.getName = function(){
- return this.name;
- }
- var b = new B(‘sven’);
- console.log(b.getName());<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
第二种运用场景跟我们的关系更加密切:
函数的参数列表arguments是一个类数组对象,虽然它也有“下标”,但它并非真正的数组,所以也不能像数组一样,进行排序操作或者往集合里添加一个新的元素。这种情况下我们常常借用Array.prototype对象上的方法。
如
- (function(){
- Array.prototype.push.call(arguments,3);
- console.log(arguments);
- })(1,2)
这种数组方法借用是可以在绝大多数浏览器中顺利执行,但由于引擎的内部实现存在差异,如果在低版本的IE中执行,必须显式地给对象a设置属性length。
所以这种数组方法的借用要满足:
o 对象本身要可以存取属性
o 对象的length属性可读写
转载地址:http://pgzxi.baihongyu.com/