this的指向

292 阅读5分钟

含义

this表示当前对象的引用

指向

  • 在方法中,this表示方法所属的对象
  • 单独使用,this表示全局对象
  • 在函数中,this表示全局对象
  • 在事件中,this表示接受事件的元素
  • 在call(),apply()中,this表示传入的参数对象

绑定规则

默认绑定,隐式绑定,显示绑定,new绑定。优先级从低到高

默认绑定

非严格模式

function say () {
    console.log(this.a);
}
var a = 1;
say();

输出:1
解析:因为函数say是直接调用(独立调用的),所以函数里面的this指向全局,全局中的a值为1,所以最后输出 为1

严格模式

function strictSay () {
    'use strict'
    console.log(this.b);
}
var b = 'b';
strictSay();

输出:Uncaught TypeError: Cannot read properties of undefined (reading 'b')
解析:严格模式下,全局对象无法使用默认的绑定,无法直接使用this,所以在输出的时候,直接报错了

隐式改变

绑定

function say() {
    console.log(this.name);
}
const doy = {
    name: 'dog',
    say: say
}
dog.say();

输出:dog
解析:此时say为dog对象上的属性,所以 this指向的是dog对象,所以输出 dog

丢失

const cat = {
    age: 1,
    say: function() {
        console.log(this.age)
    }
};
cat.say();
const say = cat.say;
say();

输出:

  • cat
  • undefined

解析:第一次调用的时候this指向的cat,第二次调用的时候this指向全局

显示绑定

call/apply

call和apply都能改变函数中的指向,将函数的this指向传入的参数。
call只接受两个参数,第一个为this需要指向的对象,第二个为函数的参数(数组形式)
appiy可以接受多个参数,第一个参数this需要指向的对象,后续参数为 函数的参数

const obj = {
    text: 'obj'
};
function getContent () {
    console.log(this.text);
}
getContent.call(obj);

输出:obj
解析:如果直接执行getContent函数,this指向全局。但是在这儿使用了call改变了函数内部的this指向,指向参数obj,所以最后输出 obj

bind

将函数绑定到某个对象,且绑定后不可以改变

function bindFunc () {
    console.log(this.content);
}
const bindObj = {
    content: 'bindObj'
}
var content = 'window';
bindFunc.bind(bindObj).bind(window)();
bindFunc();

输出:

  • bindObj
  • window 解析:bind只第一次使用的时候才会生效,第二个 bind(window)是无用代码,所以第一个输出的是 bindObj

new 绑定

function Person (age) {
    this.age = age;
}
var age = 10;
var person1 =  new Person(12);
persion1.age;

输出:12
解析:this指向对象自身

面试题

题目1 对象属性

var obj = {
    a: 10,
    b: this.a + 10,
    fn: function() {
        console.log(this.a);
    }
}
console.log(obj.b);
console.log(obj.fn());

输出:

  • NaN 解析:此时this指向的window
  • 10 解析:this指向的obj自身

题目2 声明时,决定作用域

var a = 1;
function fn() {
    var a = 2;
    console.log(a);
    console.log(this.a);
}
function fn2() {
    var a = 3;
    fn();
}
var obj = {
    a: 4,
    fn:  fn
}
fn2();
obj.fn();

输出:

  • 2 解析:a为当前(fn)作用域的变量
  • 1 解析:在fn2 中独立调用了 fn,fn中的this指向全局
  • 2 解析:a为当前(fn)作用域的变量
  • 4 解析:将fn的值赋值给obj的fn属性的值,所以执行 obj.fn 时,this指向obj

题目3 赋值改变this指向

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

输出:

  • 2 解析:this指向obj
  • 1 解析:这是一个赋值语句,最后的返回值是foo,然后再单独调用,this指向全局

题目4 this的指向

function foo (arg) {
    this.x = arg;
    return this;
}
var x = foo(1);
var y = foo(2);
console.log(x.x);
console.log(y.x);

输出:

  • Window对象(x属性存在循环引用)
  • 2 解析:两次调用都是独立调用,所以this都指向的window。var x = foo(1);执行完成之后,x的值是 window;var y = foo(2);执行完后,y的值是window,x的值是 2;所以在后续输出的时候 2.x输出的是 undefined,window.x输出的值是 2.

题目5 不同语句的返回值

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

输出:

  • 2 解析:此时this指向obj
  • 2 解析:和前一行调用一样
  • 1 解析:赋值语句,返回值为函数值,所以和单独调用foo函数一样,所以此时this指向全局
  • 1 解析:小括号运算,返回最后一个的值,所以1

面试6 严格模式下window 和 this

'use strict'
var a = 1;
function foo () {
    console.log('this1', this);
    console.log(window.a);
    console.log(this.a);
}
console.log('this2', this);
console.log(window.a);
foo();

输出:

  • this2 Window对象
  • 1
  • this1 undefined
  • 1
  • VM567:5 Uncaught TypeError: Cannot read properties of undefined (reading 'a') 解析:严格模式下,函数内部无法通过this访问到全局的window对象,单独调用时是 this为undefined

题目7 var 和 let

const a = 10;
let b = 20;
function foo () {
    console.log(this.a);
    console.log(this.b);
}
foo();
console.log(window.a);

输出:三个undefined
解析:用const 和 let定义的变量不会挂在全局,一定要注意声明使用的什么修饰。

题目8 箭头函数中的this

var name = 'window';
var obj = {
    name: 'obj',
    foo: function() {
        console.log(this.name);
        return () => {
            console.log(this.name);
        }
    },
    foo1: () => {
        console.log(this.name);
        return function () {
            console.log(this.name);
        }
    }
}
var obj2 = { name: 'obj2' };
obj.foo.call(obj2);
obj.foo().call(obj2);
obj.foo1.call(obj2);
obj.foo1().call(obj2);

输出:

  • obj2 解析:call将 obj.foo的 this 指向了obj2,所以输出obj2
  • obj obj 解析:obj.foo执行时 this指向的obj,所以输出obj;在执行call无法改变尖头函数的this的指向,所以this为上层函数this的指向,所以输出obj
  • window 解析:箭头函数this指向为上一层的this指向(call无法改变尖头函数内部this的指向),所以指向的window,输出window
  • window obj2 解析:尖头函数this指向window(上一级),call改变return出来函数的this指向,所以输出obj2

题目9 数组调用

var length = 1;
function callback() {
    return this.length;
}
var obj = {
    length: 2,
    say: function() {
        arguments[0]();
    }
}
obj.say(callback, 1, 2);

输出:3
解析:this指向arguments,所以长度时3

资料参考