JavaScript中this的指向问题

2019-03-14  本文已影响0人  椰果粒

this是什么

在JavaScript中,函数的几种调用方式

this的几种指向

示例一

var x = 111
var test = {
    x : 222
}
var temp = {
    x : 333,
    do : function(){
        alert(this.x)
    }
}
temp.do()   // 333
test.do = temp.do
test.do()   // 222
var foo = test.do
foo()       // 111

示例二

var name = 'window'
var person1 = {
  name: 'person1',
  show1: function(){
    console.log(this.name)
  }
}
var person2 = {
  name: 'person2'
}
person1.show1();              // person,this指向person1对象
person1.show1.call(person2);  // person2,this指向person2对象

示例三

var name = 'window'
var person1 = {
  name: 'person1',
  show2: () => console.log(this.name)
}
var person2 = {
  name: 'person2'
}
person1.show2();            // window,箭头函数的this和最近的普通function相同,没有,指向window
person1.show2.call(person2);// window,无法和person2绑定,所以也是window

示例四

var name = 'window'
var person1 = {
  name: 'person1',
  show3: function(){
    return function(){
      console.log(this.name);
    }
  }
}
var person2 = {
  name: 'person2'
}

person1.show3()();              // window
person1.show3().call(person2);  // person2 
person1.show3.call(person2)();  // window


// 此问题牵扯到闭包的问题

/* 
person1.show3()(); // window
等价于:
var fun = person1.show3();
fun();            // window 

里面的匿名函数被返回到person1外边,再调用这个函数时,this指向了window
*/

/* 
person1.show3().call(person2); 
等价于:
var fun = person1.show3();
fun.call(person2);      // person2 

将匿名函数的this和person2绑定了
*/

/* 
person1.show3.call(person2)();  // window
等价于
var fun = person2.show3()
fun() 

在第一阶段绑定了person2,这时候匿名函数还没执行,等再执行时,绑定到了window上
*/

示例五

var name = 'window'
var person1 = {
  name: 'person1',
  show4: function(){
    return () => console.log(this.name)
  }
}
var person2 = {
  name: 'person2'
}

person1.show4()();              // person1
person1.show4().call(person2);  // person1
person1.show4.call(person2)();  // person2

// 这里涉及了箭头函数this的指向:最近一层的普通函数绑定的this,且定义时this就被定义好了

/* 
person1.show4()(); 
等价于:
var fun = person1.show4(); // 定义时,this指向了person1
fun();           
*/


/* 
person1.show4().call(person2); 
等价于:
var fun = person1.show4();  // 定义时指向person1,而call不起作用
fun.call(person2); 
*/


/* 
person1.show4.call(person2)(); 
等价于
var fun = person2.show4()  // 将箭头函数最近的一层普通函数的this指向了person2,再执行时,this就指向了person2
fun() 
*/

示例六

var name = 'window'
function Person(name){
  this.name = name
  this.show5 = function(){
    return () => console.log(this.name)
  }
}
var personA = new Person("personA");
var personB = new Person("personB");

personA.show5()();              // personA
personA.show5().call(personB);  // personA
personA.show5.call(personB)();  // personB

示例七

var name = 'window'

function Person(name) {
  this.name = name;
  this.show1 = function () {
    console.log(this.name)
  }
  this.show2 = () => console.log(this.name)
  this.show3 = function () {
    return function () {
      console.log(this.name)
    }
  }
  this.show4 = function () {
    return () => console.log(this.name)
  }
}

var personA = new Person('personA')
var personB = new Person('personB')

personA.show1()               // personA
personA.show1.call(personB)   // personB

personA.show2()               // personA
personA.show2.call(personB)   // personA

personA.show3()()             // window
personA.show3().call(personB) // personB
personA.show3.call(personB)() // window

personA.show4()()             // personA
personA.show4().call(personB) // personA
personA.show4.call(personB)() // personB

示例八

var name = 'window'
function foo(){
  var name = 'inner';
  console.log(this.name)
}
foo();  // window
// foo在全局全局执行,this指向window
_________________________________________

var name = 'window'
function foo(){
  'use strict'
  var name = 'inner';
  console.log(this)
}
foo();  // undefined
// 这里this.name会报错,因为this是undefined
// 在严格模式下

示例九

function foo(){
  setTimeout(() => {
    console.log("id:" + this.id)
    setTimeout( () => {
      console.log("id:" + this.id)
    },100)
  },100)
}
foo.call({id:'111'})  // 111 111

function foo(){
  setTimeout(function(){
    console.log(this.id)
    setTimeout(function(){
      console.log(this.id)
    },100)
  },100)
}
foo.call({id:'111'})  //  undefined undefined


function foo1(){
  setTimeout(() =>{
    console.log("id:", this.id)
      setTimeout(function (){
        console.log("id:", this.id)
      }, 100);
  }, 100);
}
foo1.call({ id: 111 });  // 111 undefined

示例十

// 嵌套箭头函数
function foo(){
  return () => {
    return () => {
      return () => {
        console.log(this.id)
      }
    }
  }
}

var f = foo.call({id: 1});
var t1 = f.call({id: 2})()();  // 1
var t2 = f().call({id: 3})();  // 1
var t3 = f()().call({id: 4});  // 1

示例十一

var number = 2;
var obj = {
  number: 4,
  fn1: (function () { 
    console.log("定义obj的时候,立即执行函数就执行了"); 
    var number;
    this.number *= 2;
    number = number * 2;
    number = 3;
    return function () {
      var num = this.number;
      this.number *= 2;
      console.log(num);
      number *= 3;
      console.log(number);
    }
  })(),
  db2: function () {
    this.number *= 2;
  }
}

var fn1 = obj.fn1; 

console.log(number); // 4

fn1();  // 4 9
obj.fn1();  // 4 27
console.log(window.number); // 8
console.log(obj.number);  // 8


当定义obj的时候执行了匿名函数1,此时处于全局作用域内,因此上下文this是window。执行完语句(1)导致全局变量number的值变为4;执行语句(2)时临时变量number还没有被赋值,所以是NaN,但下一句会将其赋值为3;最后,匿名函数1返回了匿名函数2,因此obj.fn1=匿名函数2。(注意匿名函数2里面会用到临时变量number,老生常谈的闭包)


来到语句(3),这句会把fn1这个变量赋值为obj.fn1,也就是匿名函数2


由于全局变量number已经在语句(1)中变为了4,所以语句(4)弹出的对话框结果为4


语句(5)执行的是fn1(),它与执行obj.fn1()的区别是两者this不一样。前者为null,而后者this为obj。但是又由于JS规定,this为null时相当于全局对象window,所以这句代码执行时函数的this为window。在匿名函数2里会将全局变量number更新为8,同时将匿名函数1中被闭包的临时变量number更新为9


语句(6)的效果在上面已经分析过了,this是obj,所以obj.number更新为8,闭包的number更新为27
上一篇 下一篇

猜你喜欢

热点阅读