讨论js中this的指向问题

首先确定this的指向问题受哪些因素的影响?

与其他语言相比,函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别

在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。ES5 引入了 bind 方法来设置函数的 this 值,而不用考虑函数如何被调用的。ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)

  • 在上边这段描述中我们可以知道
  1. 大多数情况下this的值是在运行时绑定(由函数运行方式决定)
  2. this不能在执行期间赋值
  3. 严格模式和非严格模式下this有不同的效果
  4. 箭头函数中的this表现也和第一条的表现不同
  5. 可以通过bind方法设置函数的this值

尝试一下

const test = {
  prop: 42,
  func: function() {
    return this.prop;
  },
};



console.log(test.func());
// Expected output: 42

全局执行上下文

无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。

// 在浏览器中,window 对象同时也是全局对象:
console.log(this === window); // true

a = 37;
console.log(window.a); // 37


this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)    

备注:  你可以使用 globalThis 获取全局对象,无论你的代码是否在当前上下文运行。

函数执行上下文

在函数内部,this的值取决于函数被调用的方式。

  • 直接调用函数

因为下面的代码不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象,浏览器中就是 window



function f1(){

  return this;


}


//在浏览器中:
f1() === window;   //在浏览器中,全局对象是 window



//在 Node 中:
f1() === globalThis;

严格模式下直接调用函数 如果进入执行环境时没有设置 this 的值,this 会保持为 undefined

function f2(){
  "use strict"; // 这里是严格模式
  return this;


}





f2() === undefined; // true

注意 如果通过window.f2() 那么this 就指向window了

  • 调用对象的方法this指向调用方法的对象


function f1(){

  return this;


}





var obj = {
    f1,
}
//在浏览器中:
f1() === window;   //在浏览器中,全局对象是 window

// 以obj的属性调用

obj.f1() === obj // this指向了obj 

类上下文中

this 在  中的表现与在函数中类似,因为类本质上也是函数,但也有一些区别和注意事项。

在类的构造函数中,this 是一个常规对象。类中所有非静态的方法都会被添加到 this 的原型中:

class Example {
  constructor() {
    const proto = Object.getPrototypeOf(this);
    console.log(Object.getOwnPropertyNames(proto));
  }
  first(){}
  second(){}
  static third(){}
}



new Example(); // ['constructor', 'first', 'second']

Object.getPrototypeOf() Object中的静态方法,返回传入对象的原型在ES5Es2015中表现不同

箭头函数

箭头函数中,this与封闭词法环境的this保持一致。在全局代码中,它将被设置为全局对象:

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

备注:  如果将this传递给callbind、或者apply来调用箭头函数,它将被忽略。不过你仍然可以为调用添加参数,不过第一个参数(thisArg)应该设置为null

// 接着上面的代码
// 作为对象的一个方法调用
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true



// 尝试使用 call 来设定 this
console.log(foo.call(obj) === globalObject); // true

// 尝试使用 bind 来设定 this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

无论如何,foo 的 this 被设置为他被创建时的环境(在上面的例子中,就是全局对象)。这同样适用于在其他函数内创建的箭头函数:这些箭头函数的this被设置为封闭的词法环境的。

this 和对象转换

  • bind

ECMAScript 5 引入了 Function.prototype.bind()。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。

function f(){
  return this.a;
}



var g = f.bind({a:"azerty"});
console.log(g()); // azerty



var h = g.bind({a:'yoo'}); // bind 只生效一次!
console.log(h()); // azerty



var o = {a:37, f:f, g:g, h:h};
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty
  • apply、call
function add(c, d) {
  return this.a + this.b + c + d;
}



var o = {a: 1, b: 3};


// 第一个参数是用作“this”的对象
// 其余参数用作函数的参数
add.call(o, 5, 7); // 16



// 第一个参数是用作“this”的对象
// 第二个参数是一个数组,数组中的两个成员用作函数参数
add.apply(o, [10, 20]); // 34

在非严格模式下使用 call 和 apply 时,如果用作 this 的值不是对象,则会被尝试转换为对象。null 和 undefined 被转换为全局对象。原始值如 7 或 'foo' 会使用相应构造函数转换为对象。因此 7 会被转换为 new Number(7) 生成的对象,字符串 'foo' 会转换为 new String('foo') 生成的对象。

总结一下

“this“` 的指向需要考虑当前的执行环境 是否严格模式 是否为箭头函数三个点

  1. 全局上下文中: 严格模式和非严格模式表现一直都指向 全局对象 浏览器指向 window node环境指向globalThis
  2. 函数上下文中:
  • 箭头函数中this 被设置为他被创建时的环境 且不受调用者和 bind call apply的影响
  • 普通的函数申明
    • 直接调用时:严格模式下 this指向undefined 非严格模式下指向 window
    • 通过对象调用时 指向调用该函数的对象
  1. 改变函数执行期间的this指向
  • call、apply:对箭头函数没有效果
  • bind:对箭头函数没有效果,并且只在第一次调用bind时生效

4.可以使用 globalThis 获取全局对象,无论你的代码是否在当前上下文运行

自己做的笔记,如果有错误的地方,希望路过的大佬们指正

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MY0q2CM6' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片