前端里的this指向问题

目录

1.代码输出结果

2.代码输出结果

3.代码输出结果

4.代码输出结果

5.代码输出结果

6.代码输出结果

7.代码输出结果

8.代码输出结果

9.代码输出结果

10.代码输出结果

11.代码输出结果

12.代码输出结果

13.代码输出结果

14.代码输出结果

总结


1.代码输出结果

function foo() {
  console.log( this.a );
}

function doFoo() {
  foo();
}

var obj = {
  a: 1,
  doFoo: doFoo
};

var a = 2; 
obj.doFoo()

输出结果为2,因为执行foo的是doFoo函数,函数默认执行window

但是如果doFoo函数里:

function doFoo() {
        // foo();
        console.log(this.a);//1
      }

输出的就是1,因为执行它的是obj对象,会隐式的把this指向obj对象

2.代码输出结果

var a = 10
var obj = {
  a: 20,
  say: () => {
    console.log(this.a)
  }
}
obj.say() //10  


var anotherObj = { a: 30 } 
obj.say.apply(anotherObj) //10

输出结果为10;10

apply或者bind通过绑定会指向里面的参数

但是这个是往外翻两层到window这层,所以都是最外层的a=10

如果换成普通函数的话就是20;30

3.代码输出结果

function a() {
  console.log(this);
}
a.call(null);

输出结果为window

call里面的参数如果是null或者undefined的话,this就会指向全局对象(浏览器里是window)

但是在严格模式情况下,参数是null输出的就是null;参数是undefined输出的是undefined

4.代码输出结果

var obj = { 
  name: 'cuggz', 
  fun: function(){ 
     console.log(this.name); 
  } 
} 
obj.fun()     // cuggz
new obj.fun() // undefined

第二个new是取出了obj里的fun作为新的构造函数,所以里面没有name参数,结果为undefined

5.代码输出结果

var obj = {
   say: function() {
     var f1 = () =>  {
       console.log("1111", this);
     }
     f1();
   },
   pro: {
     getPro:() =>  {
        console.log(this);
     }
   }
}
var o = obj.say;
o();
obj.say();
obj.pro.getPro();

第一个:o=obj.say然后再调用o(),其实相当于是:

o=function() {
     var f1 = () =>  {
       console.log("1111", this);
     }
     f1();
   },

而且里面是箭头函数,翻第一层到f1,第二层到o,o是一个函数,它拥有this,与o平级的this就是window

第二个:obj.say() 翻第一层到f1,第二层到say,say平级的this就是obj

第三个:obj.pro.getPro()第一层翻到getPro,翻第二层到pro(注意对象是没有this 的!!只有函数有!),所以第二层直接翻到最外层,this就是window

对象不构成单独的作用域=>没有this

6.代码输出结果

var myObject = {
    foo: "bar",
    func: function() {
        var self = this;
        console.log(this.foo);  
        console.log(self.foo);  
        (function() {
            console.log(this.foo);  
            console.log(self.foo);  
        }());
    }
};
myObject.func();

func是myObject调用的,所以func里面的this是myObject,那么self也是

this.foo就是bar

self.foo也是bar

下面的函数被调用,里面作用域的this是func,所以它里面没有foo属性,输出undefined

然后最后一个self.foo,这块是一个闭包,里面函数可以调用外层函数的属性self.foo===bar

7.代码输出结果

window.number = 2;
var obj = {
 number: 3,
 db1: (function(){
   console.log(this);
   this.number *= 4;
   return function(){
     console.log(this);
     this.number *= 5;
   }
 })()
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);     // 15
console.log(window.number);  // 40

⚠️注意:obj.db1是个立即执行函数,它在obj对象定义完之后就会执行,然后返回后面的函数

所以在下面一系列调用函数之前就会有一次输出window,而且此时window上的number=8,在非严格模式下,自执行函数IIFE输出的this就是window

所以第一次先会输出一个window,此时这个函数变成了这样:

window.number = 2;
var obj = {
 number: 3,
 db1: function(){
     console.log(this);
     this.number *= 5;
  }
}
var db1 = obj.db1;
db1();
obj.db1();
console.log(obj.number);     // 15
console.log(window.number);  // 40

db1=obj.db1之后,db1如下:

db1=function(){
     console.log(this);
     this.number *= 5;
  }

打印这个this就是window(db1时函数不是对象),此时window . number=5*8=40

然后调用obj.db1(),this打印obj对象,obj.number=3*5=15

8.代码输出结果

var length = 10;
function fn() {
    console.log(this.length);
}
 
var obj = {
  length: 5,
  method: function(fn) {
    fn();
    arguments[0]();
  }
};
 
obj.method(fn, 1);

fn()这样调用只是一个普通函数,而不是作为对象的方法去调用,所以this是window,输出10

而arguments承接参数fn和1,但是这次相当于arguments(因为它是个类数组对象!)去调用方法,所以this指向arguments,而且它是伪数组有length,输出2

9.代码输出结果

var a = 1;
function printA(){
  console.log(this.a);
}
var obj={
  a:2,
  foo:printA,
  bar:function(){
    printA();
  }
}

obj.foo(); // 2
obj.bar(); // 1
var foo = obj.foo;
foo(); // 1

obj.foo(),foo里的this指向obj;它跟上面的区别是:上面那个只是由obj穿参的,但是不是obj去调用的,只是函数进行到那里去调用了,不是对象调用的,而这个就是obj调用的,所以this是obj;

obj.bar(),现在printA函数就不是由obj对象调用而进行的了,所以printA函数里的this是全局对象,输出1;

var foo=obj.foo,那么foo相当于(foo是函数):

全局上的foo:printA,this是window,输出1

10.代码输出结果

var x = 3;
var y = 4;
var obj = {
    x: 1,
    y: 6,
    getX: function() {
        var x = 5;
        return function() {
            return this.x;
        }();
    },
    getY: function() {
        var y = 7;
        return this.y;
    }
}
console.log(obj.getX()) // 3
console.log(obj.getY()) // 6

第一个:又是一个立即执行函数,IIFE里面的this指向全局对象,所以x=3

第二个:调用对象是obj,this是obj的this,输出6

11.代码输出结果

 var a = 10; 
 var obt = { 
   a: 20, 
   fn: function(){ 
     var a = 30; 
     console.log(this.a)
   } 
 }
 obt.fn();  // 20
 obt.fn.call(); // 10
 (obt.fn)(); // 20

obt.fn()调用者是obj,所以函数里的this是obj,输出obj的a,20

obt.fn.call(),call用来改变this,但是里面的参数为空(null),call里的参数为undefined或者null,this就是全局对象window,所以输出a为10

()的作用是改变运算顺序,所以这个跟第一个没什么区别,输出20

12.代码输出结果

function a(xx){
  this.x = xx;
  return this
};
var x = a(5);
var y = a(6);

console.log(x.x)  // undefined
console.log(y.x)  // 6

x一开始相当于:

var x=function a(5){

this.x=5;

return this

}

没有对象调用这个函数,所以this.x说的是window.x=5,最后return this => window,返回的window又赋值回给var x了,所以最外层的window.x=window,x.x=undefined

顺序:

window.x=5

var x=window=>window.x=window

y一开始相当于:

var y=function a(6){

this.x=6;

return this

}

window上的x=6,返回window赋值给y

顺序:

window.x=6

window=y

输出y.x=6

13.代码输出结果

function foo(something){
    this.a = something
}

var obj1 = {
    foo: foo
}

var obj2 = {}

obj1.foo(2); 
console.log(obj1.a); // 2

obj1.foo.call(obj2, 3);
console.log(obj2.a); // 3

var bar = new obj1.foo(4)
console.log(obj1.a); // 2
console.log(bar.a); // 4

先是调用obj1.foo(2),obj1去调用的函数,所以obj1里的a是2,下面输出为2

然后obj1.foo.call(obj2,3),obj2上的a赋值为3

var bar=new obj1.foo(4)这是又new了一个,所以不会赋值之前的2,obj1上的a输出还是2

bar相当于:

var bar=function foo(){},注意new出来的比隐式绑定优先级高,所以里面的this是bar,bar的a就是4

14.代码输出结果

function foo(something){
    this.a = something
}

var obj1 = {}

var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); // 2

var baz = new bar(3);
console.log(obj1.a); // 2
console.log(baz.a); // 3

这一步相当于:

var bar=function foo(sm){

this.a=sm;(this是obj1)

},obj1上

bar(2)=> obj1.a=2

var baz= new bar(3),new出来的比bind绑定的优先级高,所以this是baz,baz上的a为3

总结

改变this指向的四种方式:

函数默认指向,this是window

对象调用函数,函数里的this指向对象

显示绑定:call、apply、bind绑定,有参数绑定参数,null或者undefined就是window

通过new绑定this

其中new>显示>对象调用>默认指向

箭头函数里的this是一开始就定义好的,与后来谁去调用没有关系,this会继承自定义时的外层作用域,而且对象不会创建作用域,所以往外翻的时候只能翻到函数上

就比如这张图,obj.say()第一层到f1函数,第二层到say函数,然后找与say函数平级的this

obj.pro.getPro()第一层到getPro函数,第二层到最外层window

还有一些特殊情况比如立即执行匿名函数IIFE,在非严格模式下this就是window

相关推荐
哥坐11路4 分钟前
网络IP跳动问题解决详
开发语言·php
奔跑吧邓邓子27 分钟前
【Python爬虫(27)】探索数据可视化的魔法世界
开发语言·爬虫·python·数据可视化
Ama_tor29 分钟前
网页制作05-html,css,javascript初认识のhtml表格的创建
javascript·css·html
白嫖不白嫖33 分钟前
网页版的俄罗斯方块
前端·javascript·css
饼干饿死了35 分钟前
实现动态翻转时钟效果的 HTML、CSS 和 JavaScript,附源码
javascript·css·html
林的快手37 分钟前
CSS文本属性
前端·javascript·css·chrome·node.js·css3·html5
code bean38 分钟前
【C# 数据结构】队列 FIFO
开发语言·数据结构·c#
Shuzi_master71 小时前
<02.21>八股文
java·开发语言
元亓亓亓1 小时前
java后端开发day18--学生管理系统
java·开发语言
EPSDA1 小时前
Linux线程池
linux·运维·服务器·开发语言·c++