javascript 之this指针-11

2018-01-12 21:19:52来源:cnblogs.com作者:风吹De麦浪人点击

分享

 前言

在《javascript 之执行环境-08》文中说到,当JavaScript代码执行一段可执行代码时,会创建对应的执行上下文(execution context)。对于每个执行上下文,都有三个重要属性:

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this

  JavaScript中的this跟其他语言有些不一样,比如Java .net语言中的this是在代码的执行阶段是不可变的,而JavaScript的this是在调用阶段进行绑定。也因为这一性质给了this很大的灵活性,即当函数在不同的调用方式下都可能会导致this的值不同;

定义

  this 对象是在运行时基于函数的执行环境绑定的,跟函数的调用位置有关而不是声明的位置;可以理解为this是在函数调用阶段绑定,也就是执行上下文创建的阶段进行赋值,保存在变量对象中;

四种绑定规则

new 构造函数绑定,this指向新创建的对象

 1 function createPerson(){ 2        return new person(); 3     } 4     function person() { 5         this.name = "Joel"; 6         this.say=function(){ 7             console.log(p) 8             console.log('hello' + this.name) 9         }10     }11     var p = new person();12     p.say();13     console.log(p.name);//Joel14     console.log('开始')15     var t=createPerson();16     t.say();

不管是直接new 还是通过function createPerson 函数返回的对象,this 都是指向了新创建出来的对象;

显示绑定,this指向传进去的对象

 1     //call() apply() bind() 显示绑定 2     window.color = "red"; 3     var Obj = { color: "blue" }; 4     function sayColor() { 5         console.log(this.color); 6     } 7     sayColor();// red this window 8     sayColor.call(this);//red 9     sayColor.call(window);//red10     sayColor.call(Obj);// blue 把this指针改为对象Obj11     sayColor.apply(Obj);//blue 把this指针改为对象Obj12     sayColor.bind(Obj)();//blue 把this指针改为对象Obj

如果你把null/undefined作为this的绑定对象传入call/apply/bind,这些值在调用时会被忽略,实际用的是默认的绑定规则;

1   function foo() {2       console.log(this.a)3     }4    var a=2;5     foo.call(null);//26     foo.call(undefined);//2

隐士绑定

以对象的方法形式调用,this指向当前这个对象

 1    function foo(){ 2         console.log(this)//{a: 2, name: "Joel", foo: ƒ} 3         console.log(this.a)//2 4     } 5     var obj={ 6         a:2, 7         name:'Joel', 8         foo:foo 9     };10     obj.foo();

这时this指向当前obj对象,但是如果换种写法会造成this 丢失问题。

 1     function foo(){ 2         console.log(this)//{a: 2, name: "Joel", foo: ƒ} 3         console.log(this.a)//2 4     } 5     var obj={ 6         a:2, 7         name:'Joel', 8         foo:foo 9     };10     obj.foo();11     //this 丢失的问题12     var t= obj.foo;13     t(); //window undefined

变量t此时保存的是函数的引用跟obj已经没有关系,所以此时this指向window。

默认绑定 严格模式下this 绑定到undefined,否则绑定到全局对象 window

 1   function foo(){ 2         console.log(this)//window 3         console.log(this.a)//Joel 4     } 5     var a='Joel'; 6     foo(); 7  8     //严格模式 9     function fo(){10         'use strict'  //严格模式11         console.log(this)//undefined12         console.log(this.b)//报错 Cannot read property 'b' of undefined13     }14     var b='Joel';15     fo();

以上是基本的this绑定规则,其中new、显示绑定很容易判断,其中比较容易错的是容易把默认绑定误认为是隐士绑定 如匿名函数、闭包、函数当做参数等;

独立调用:this 指向window

 1   var name='Joel',age=12; 2     function say(){ 3         function say1(){ 4             console.log(this.name);//window 5             function say2(){ 6                 name+='-l' 7                 console.log(this.name);//window 8             } 9             say2()10         }11         say1();12     }13     say();14 15     //匿名函数16     (function(){17        console.log(this.name)18     })()

function 当做参数传递其实跟独立调用一样的原理

 1 function foo() { 2         console.log(this)//window 3         console.log(this.a)//oops global 4     } 5     function doFoo(fn) { 6         console.log(this);//window 7         fn();//类似与 foo() 8     } 9     var obj = {10         a: 2,11         foo: foo12     }13     var a = 'oops global';14     doFoo(obj.foo);

同理setTimeout 也是一样

 1  var obj = { 2         a: 2, 3         foo: function() { 4             console.log(this);  5         }, 6         foo2: function() { 7             console.log(this);   //this 指向 obj  8             setTimeout(this.foo, 1000);   // this 指向 window  9         }10     }11     var a = 'oops global';12     obj.foo2();

闭包中的this

 1     var name = "Joel"; 2     var obj = { 3         name: "My object", 4         getName: function() { 5             // var that = this;   // 将getNameFunc()的this保存在that变量中 6             return function() { 7                 return this.name; 8             }; 9         }10     }11     console.log(obj.getName()());   // "Joel"

这里的虽然是对象的方法形式调用obj.getName(),在getName中的this是指向obj,但是返回的匿名函数中的this 为什么是window呢?

把最后的一句拆成两个步骤执行:

1 var t=obj.getName();2 t();

是不是有点像在独立调用呢?如果需要访问obj中的name,只需要把this对象缓存起来,在匿名函数中访问即可,把var that=this;去掉注释即可;

总结

  • this 是变量对象的一个属性,是在调用时被绑定的,跟函数的调用位置有关而不是声明的位置;
  • 找到调用位置,根据绑定规则来分析this 绑定;
  • 默认绑定严格模式下this 绑定到undefined,否则绑定到全局对象 window;

思考题

 1     var length = 5; 2     var obj = { 3         foo: function (fn) { 4             console.log(this.length); // this => obj 5             fn(); // this => window 6             arguments[0](); // this => arguments 7             var bar = arguments[0]; 8             bar(); // this => window 9         },10         length: 1011     }12     var fn = function () {13         console.log(this.length);14     }15     obj.foo(fn);16     //10, 5, 1, 5

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台