js中this的指向问题

js中this的指向问题_第1张图片

1、全局对象的 this 指向

全局对象的 this 指向 window 对象(所在作用域?)

  var a = 1000;
  var obj = {
      a: 1,
      b: this.a+1
  }
  //普通对象 obj 没有 this,里面访问的 this指向 window 对象。
  console.log(obj.b);//1001

2、全局作用域或者普通函数中 this 指向全局对象 window

如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window

//直接打印
console.log(this) //window

//function声明函数
function bar () {console.log(this)}
bar() //window

//function声明函数赋给变量
var bar = function () {console.log(this)}
bar() //window

//自执行函数
(function () {console.log(this)})(); //window

函数中调用另一个函数

  function foo() {
    console.log(this); // window
  }
  function bar() {
    console.log(this); // window
    // 直接调用
    foo();
  }
  // 直接调用
  bar();

全局函数执行 this 指向 window

  function fun(){
      console.log(this === window)   //true
  }

  var name = "William";
  function test(){
      var name = "Lisi";
      let a = {
          name: this.name
      }
      console.log(a.name);
  }
  test();//William

3、this 永远指向最后调用它的那个对象

this 永远指向最后调用它的那个对象,适用于非箭头函数的调用
(隐式绑定:函数还可以作为某个对象的方法调用,这时this就指这个上级对象)

  var a = 1000;
  function fun(){
      var obj = {
          a: 1,
          c: this.a + 2
      }
      return obj.c;
  }  
  //fun 函数执行的时候内部 this 指向 window
  console.log(fun());//1002
  let obj = {
      name: "William",
      say: function(){
          console.log(this.name);
      }
  }
  //say 函数在执行的时候,是被 obj 对象调用的,所以指向的是 obj 对象,this.name 访问的是 obj.name
  obj.say();//William
var o = {
    a:10,
    b:{
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();//undefined

分析:这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();

分析:结合第七点看,同时,记住,this永远指向的是最后调用它的对象,虽然fn是对象b的方法,但是fn赋值给j时候并没有执行,所以最终指向window

var obj = {
    number: 1,
    getOwnNumber: function () {
        var number = 2;
        return this.number;
    },
    getNumber: function () {
        var number = 3;
        return function () {
            var number = 4;
            return this.number;
        };
    }
}
console.log(obj.getOwnNumber());//1
console.log(obj.getNumber()());//undefined

分析:

obj.getNumber()运行结果是一个匿名函数,然后再执行匿名函数
过程拆分为:
var fun = obj.getNumber() // 返回一个匿名函数
fun();
所以此处this指向window对象

4、new 关键词改变了 this 指向

  const a = 1000;
  function f1(a, b){
      this.a = a;
      this.b = b;
      console.log(this===window);
  }
  f1();                                  //true
  const f = new f1(1,2);                //false
  console.log(f.a);//1

分析:
new 操作符做了什么?

1、首先内部创建了一个空对象 obj
2、将新对象的__proto__指向构造函数的 prototype 对象
3、将构造函数的作用域赋值给新的对象(也就是this 指向新对象)
4、执行构造函数中的代码(为这个新对象添加属性)
5、返回apply执行的结果或者返回对象

  //模拟 new 代码
  function create(fn, ...rest){
      const obj = Object.create(fn.prototype);
      const result = fn.apply(obj, rest);
      if(typeof result === "object"){
          return result;
      }else{
          return obj;
      }
  }

再列举一些特殊情况:

function fn()  
{  
    this.user = 'xxx';  
    return {};  
}
var a = new fn();  
console.log(a);//{}
//new过程遇到return一个对象,此时this指向为返回的对象
//实质还是他调用的对象
console.log(a.user); //undefined

拓展:
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。

function fn()  
{  
    this.user = 'sweet';  
    return function(){};
}
var a = new fn;  
console.log(a.user); //undefined
function fn()  
{  
    this.user = 'sweet';  
    return 1;
}
var a = new fn;  
console.log(a.user); //sweet
function fn()  
{  
    this.user = 'sweet';  
    return undefined;
}
var a = new fn;  
console.log(a.user); //sweet
function fn()  
{  
    this.user = 'sweet';  
    return null;
}
var a = new fn;  
console.log(a.user); //sweet

5、apply()、call()、bind()

apply call bind 可以改变 this 指向,准确的说是改变非箭头函数的 this 指向。

  let obj = {
      name: "William",
      say: function(){
          console.log(this.name);
      }
  }
  obj.say();//William
  obj.say.apply({name: "Ben"})//Ben

6、箭头函数的 this

箭头函数的 this 在定义时确定。
箭头函数 this 指向:箭头函数没有自己的 this,看其外层的是否有函数,如果有,外层函数的 this 就是内部箭头函数的 this,如果没有,则 this 是 window。

箭头函数的特性:

  • 箭头函数的 this 在定义时确定
  • 箭头函数没有prototype属性,是更纯粹的函数。
  • 箭头函数不能使用new 关键字。
  • 箭头函数没有 arguments,可以使用 …rest 解决参数不定长的问题
  • apply call bind 不能修改箭头函数的 this
    js中this的指向问题_第2张图片
    通过 Babel 将 ES6 的代码进行转义,可以看到箭头函数的 this 在定义的时候会进行一个转换,所以说箭头函数的 this 在定义的时候确定
 window.color = "red";
  let color = "green";
  // var color = "black";
  let obj = {
    color: "blue"
  };
  let sayColor = () => {
    return this.color;
  };
  console.log(sayColor.apply(obj));//red

分析:

1、sayColor 是一个箭头函数,applay 是不起作用的,所以函数里面的this 没有被改变。这里箭头函数里面的 this 按照定义的时候 this 的指向的。定义 sayColor 的时候 this 指向全局 window。
2、this.color 指的是 window.color。又 let const 定义的变量并不会加载到 window 上面的。所以 let color并不会改变 window.color的值

拓展

const obj = {
  sayThis: () => {
    console.log(this);
  }
};

obj.sayThis(); // window    因为 JavaScript 没有块作用域,所以在定义 sayThis 的时候,里面的 this 就绑到 window 上去了
const globalSay = obj.sayThis;
globalSay(); // window 浏览器中的 global 对象

7、匿名函数的 this

匿名函数的 this 永远指向 window ,没有变量指向匿名函数的执行环境具有全局性,因此其 this 对象通常指向 window。

 var name = "The window";
  var object = {
    name: 'My Object',
    //obj.getNameFunc 指向了后面的匿名函数
    getNameFunc: function () {
      console.log(this);//object
      return function () {
          return this.name;
      }
    },
    getName: function () {
    //此时,箭头函数的this指向就是当前所在环境了,不像上面没有指向的匿名函数会都指向window
      return ()=>{
        return this.name;
      }
    }
  }
  console.log(object.getNameFunc()());//The window
  console.log(object.getName()());//My Object

你可能感兴趣的:(笔记,前端面试,javascript,前端,this指向)