深入了解Javascript的this

目录

1.this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用者是谁

2.对象嵌套、函数嵌套中的this

3.在严格模式和非严格模式中全局调用普通函数的区别

4.构造函数调用中的this

5.call 和 apply 方法调用

6.bind 方法调用

7.箭头函数中的this

8.总结


 

1.this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数的调用者是谁

var getName = function() {
    return this.name;
};

var person1 = {
    name: 'Alice',
    getName: getName
};

var person2 = {
    name: 'Bob',
    getName: getName
};

console.log(person1.getName());    // Alice
console.log(person2.getName());    // Bob

下面的例子中,直接运行 obj.fn() ,调用该函数的上一级对象是 obj,所以 this 指向 obj,得到 this.x 的值是 2;之后我们将 fn 方法首先赋值给变量 a,a 运行在全局环境中,所以此时 this 指向全局对象Window,得到 this.x 为 1。

var x = 1
var obj = {
    x: 2,
    fn: function() {
        console.log(this);    
        console.log(this.x);
    }
}

obj.fn()     

// obj.fn()结果打印出
// Object {x: 2, fn: function}
// 2

var a = obj.fn
a()   

// a()结果打印出:   
// Window 全局对象
// 1

2.对象嵌套、函数嵌套中的this

对象嵌套。this 始终会指向直接调用函数的上一级对象,即 y。

var x = 1
var obj = {
  x: 2,
  y: {
    x: 3,
    fn: function() {
      console.log(this);   
      console.log(this.x); 
    }
  }
}

obj.y.fn();   
//打印结果为:
// Object {x: 3, fn: function}
// 3

函数嵌套。在函数 y 中,this 指向了调用它的上一级对象 obj。但是在嵌套函数 fn 中,this 并不指向 obj。嵌套的函数不会从调用它的函数中继承 this,当嵌套函数作为函数调用时,其 this 值在非严格模式下指向全局对象,在严格模式是 undefined

var obj = {
    y: function() {
        console.log(this === obj);   
        console.log(this);   
        fn();

        function fn() {
            console.log(this === obj);   
            console.log(this);   
        }
    }
}

obj.y();  
//打印结果为:
// true
// Object {y: function}
// false
// Window 全局对象

3.在严格模式和非严格模式中全局调用普通函数的区别

如果普通函数是在全局环境中被调用,在非严格模式下,普通函数中 this 也指向全局对象;如果是在严格模式下,this 将会是 undefined。

function f1 () {
    console.log(this)
}
function f2 () {
    'use strict'
    console.log(this)
}
f1() // window
f2() // undefined
//--非严格模式--
var x = 1
function fn() {
    console.log(this);   // Window 全局对象
    console.log(this.x);  // 1
}
fn(); 
//--严格模式--
"use strict"     // 使用严格模式
var x = 1
function fn() {
    console.log(this);   // undefined
    console.log(this.x);  // 报错 "Cannot read property 'x' of undefined",因为此时 this 是 undefined
}
fn(); 

在严格模式下,在全局作用域中,this指向window对象。

//--严格模式--
"use strict"     // 使用严格模式
console.log(this);   // Window全局对象

4.构造函数调用中的this

使用 new 关键字,通过构造函数生成一个实例对象。此时,this 便指向这个新对象

var x = 1;

function Fn() {
   this.x = 2;
    console.log(this);  // Fn {x: 2}
}

var obj = new Fn();   // obj和Fn(..)调用中的this进行绑定
console.log(obj.x)   // 2

如果构造函数返回了引用类型,this 将指向实例化的新对象。因为Fn()返回(return)的是一个对象(引用类型),this 会指向这个return的对象。

var x = 1
function Fn() {
  this.x = 2 
  return {x: 3}
}

var a = new Fn()
console.log(a.x)      // 3

如果return的是一个非引用类型的值,this将被绑定到new Fn()构造的新对象a。

var x = 1
function Fn() {
  this.x = 2
  return 3
}

var a = new Fn()
console.log(a.x)      // 2

5.call 和 apply 方法调用

如果你想改变 this 的指向,可以使用 call 或 apply 方法。它们的第一个参数都是指定函数运行时其中的this指向。如果第一个参数不传(参数为空)或者传 null 、undefined,默认 this 指向全局对象(非严格模式)或 undefined(严格模式)。

var x = 1;
var obj = {
  x: 2
}
function fn() {
    console.log(this);
    console.log(this.x);
}

fn.call(obj)
// Object {x: 2}
// 2

fn.apply(obj)     
// Object {x: 2}
// 2

fn.call()         
// Window 全局对象
// 1

fn.apply(null)    
// Window 全局对象
// 1

fn.call(undefined)    
// Window 全局对象
// 1

call 和 apply 的区别在于,call 的第二个及后续参数是一个参数列表,apply 的第二个参数是数组。

var x = 1
var obj = {
  x: 2
}
function Sum(y, z) {
  console.log(this.x + y + z)
}

Sum.call(obj, 3, 4)       // 9
Sum.apply(obj, [3, 4])    // 9

6.bind 方法调用

调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,新函数的 this 会永久的指向 bind 传入的第一个参数,无论这个函数是如何被调用的。

var x = 1
var obj1 = {
    x: 2
};
var obj2 = {
    x: 3
};
function fn() {
    console.log(this);
    console.log(this.x);
};

var a = fn.bind(obj1);
var b = a.bind(obj2);

fn();
// Window 全局对象
// 1

a();
// Object {x: 2}
// 2

b();
// Object {x: 2}
// 2

a.call(obj2);
// Object {x: 2}
// 2

7.箭头函数中的this

ES6中新增的()=>箭头函数。箭头函数中使用的this,其实是直接包含它的那个函数或函数表达式中的this。

箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window

var obj = {
  y: function() {
        console.log(this === obj);   // true
        console.log(this);           // Object {y: function}

      var fn = () => {
          console.log(this === obj);   // true
          console.log(this);           // Object {y: function}
      }
      fn();
  }
}

obj.y() 

下例中,虽然存在两个箭头函数,其实this取决于最外层的箭头函数,由于obj是个对象而非函数,所以this指向为Window全局对象。

var obj = {
  y: () => {
        console.log(this === obj);   // false
        console.log(this);           // Window 全局对象 
       
      var fn = () => {
          console.log(this === obj);   // false
          console.log(this);           // Window 全局对象 
      }
      fn();
  }
}

obj.y() 

同 bind 一样,箭头函数也很“顽固”,我们无法通过 call 和 apply 来改变 this 的指向,即传入的第一个参数被忽略

var x = 1
var obj = {
    x: 2
}
var a = () => {
    console.log(this.x)
    console.log(this)
}

a.call(obj)       
// 1
// Window 全局对象

a.apply(obj)      
// 1
// Window 全局对象

8.总结

用一张流程图总结:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值