JavaScript的奇妙this

更新日期: 2019-06-01阅读: 1.2k标签: this
this 关键字是 JavaScript 中最复杂的机制之一。它是一个很特别的关键字,被自动定义在所有函数的作用域中。但是即使是非常有经验的 JavaScript 开发者也很难说清它到底指向什么。


this是什么?

指向函数本身?

光从字面意思上来看,很容易让人觉得this就是指向函数本身,事实上真是这样吗?我们可以看一个例子。

function foo() {
    this.count = this.count ? this.count + 1 : 1;
}

for (let i = 0; i < 5; i++) {
    foo();
}
console.log(foo.count); // undefined

可以看到,foo.count输出的并不是我们期待的5,而是一开始赋值的0。也就是说this其实并没有指向函数本身

指向作用域?

还有一种比较常见的误解是,this指向了函数的作用域。

function foo() {
    var a = 2;
    bar();
}
function bar() {
    console.log(this.a);
}

foo(); // undefined

这段代码中,bar在foo中运行,输出this.a得到的却是undefined。也就是说this也不是指向函数的作用域的

这也不是,那也不是,this到底是什么呢?在函数执行过程中,会创建一个执行上下文(一个记录),this就是这个上下文中的一个属性,在执行过程中用到。而this的指向则是取决于函数在哪里被调用。


this的绑定规则

this的绑定有四条可以遵循的规则,下面将一一介绍。

1.默认绑定

独立函数调用,非严格模式下,指向window;严格模式下指向undefined。 这里说的独立函数可以理解成除开后面三种情况的一般函数调用。

// 非严格模式
var name = 'Willem';
function foo() {
    console.log(this.name);
}
foo(); // Willem

// 执行时启用严格模式
(function() {
    'use strict';
    foo(); // Willem
    bar(); // Cannot read property 'name' of undefined
})();

// 函数体使用严格模式
function bar() {
    'use strict';
    console.log(this.name);
}

上述代码中,分别在普通环境中输出Willem,说明指向的确实是window对象。需要特别注意的一点是:严格模式下指向undefined指的是函数体内启用了严格模式,而不是调用时。

2. 隐式绑定

隐式绑定说的是,在函数执行时,是否被某个对象拥有或包含。换句话说,在函数运行时,是否是作为某个对象的属性的方式运行的,这样说还是不是很清楚,来个栗子:

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

示例中,foo被当做了obj的一个属性进行执行,此时obj作为了函数的上下文,此时this指向了obj,this.a等价于obj.a。在对象属性链式的调用中,只有最后一层会对调用位置产生影响,也就是说最后一层会影响this指向。

有很多前端的小伙伴面试时或许还见过这样的题:

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

这是隐式绑定最常见的一个问题,隐式丢失:被隐式绑定的函数会丢失绑定对象。虽然bar是对obj.foo的一个引用,但实际上引用的还是foo函数本身,bar函数就是一个独立函数的调用,参考第一条,此时this指向了window|undefined。

还有一种经典的回调函数的this指向问题也是隐式丢失。

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

小结:在隐式绑定中,赋值的情况下(回调是隐式赋值)需要特别注意隐式丢失的问题 。

3. 显示绑定

JavaScript中的Function提供了两个方法call和apply,传入的第一个参数是一个对象,会把this绑定到这个对象。如果是传入的是一个原始值(字符串、数字、布尔),会被转换成它的对象形式(new String(), new Boolean(), new Number())。

function foo() {
    console.log(this.a);
}
var obj = {
    a: 1
};
foo.call(obj); // 1

虽然我们可以使用call和apply显式指定this的指向,但是还是会存在丢失绑定的问题。可以通过所谓的硬绑定(bind函数)来解决,这里就不过多赘述了。

4. new

最后要介绍的是使用new来做this的绑定的修改,有手动实现过new的童鞋应该比较清楚,js中的new和其他语言的new完全不同。
new的执行过程:

  1. 创建一个空对象
  2. 当前空对象执行原型对接
  3. 返回函数执行结果或者当前这个空对象
function Foo(a) {
    this.a = a;
}

var bar = new Foo(2);
bar.a; // 2

使用 new 来调用函数时,我们会构造一个新对象并把它绑定到 函数调用中的 this上。


优先级

最后简单说一下优先级的关系:new > 显示绑定 > 隐式绑定 > 默认绑定。


链接: https://www.fly63.com/article/detial/9240

解读Javascript中的this机制,别再为了 this 发愁了

JavaScript中有很多令人困惑的地方,或者叫做机制。但是,就是这些东西让JavaScript显得那么美好而与众不同。比方说函数也是对象、闭包、原型链继承等等,而这其中就包括颇让人费解的this机制。

js中this的详细解释,JavaScript中this绑定规则【你不知道的JavaScript】

this的绑定过程之前的调用栈 和 调用位置,this绑定规则:1、默认模式,2、隐式绑定,3、显式绑定,4、new绑定

JavaScript中this的运行机制及爬坑指南

在 JavaScript 中,this 这个特殊的变量是相对比较复杂的,因为 this 不仅仅用在面向对象环境中,在其他任何地方也是可用的。 本篇博文中会解释 this 是如何工作的以及使用中可能导致问题的地方,最后奉上最佳实践。

JS中this的指向问题(全)

this关键字在js中的指向问题不管是工作还是面试中都会经常遇到,所以在此对它进行一下总结:全局作用域中、闭包中指window、函数调用模式:谁调用就指谁、构造函数中,this指实例对象、apply/call改变this的指向、bind改变this指向等

彻底淘汰并消除JavaScript中的this

如果这很难明白,为什么我们不停止使用它呢?认真的思考一下?如果你读过 将90%的垃圾扔进垃圾桶后,我如何重新发现对JavaScript的爱, 当我说扔掉它时,你不会感到惊讶,this被丢弃了

JavaScript this常见指向问题

this的用法:直接在函数中使用 谁调用这个函数this就指向谁 ,对象中使用, 一般情况下指向该对象 ,在构造函数中使用

JavaScript函数中this的四种绑定策略

this的四种绑定策略:默认绑定、隐式绑定、显示绑定、new绑定。首先要明确的是一般情况下,this不是函数被定义时绑定,而是函数被调用时被绑定 ,那么函数中的this有四种绑定方式:

改变this的指向

this是Javascript语言的一个关键字。它代表函数运行时,自动生成的一个内部对象.this永远指向函数的调用者。随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。

js手写实现apply,call,bind

apply和call的区别就是传的参数形式不一样。call是一个一个的传,apply可以将参数以数组的形式传进去。而bind是传入第二个和后面的参数,且绑定this,返回一个转化后的函数。

this指向问题的经典场景

以函数形式调用,this指向window;以方法形式调用,this指向调用方法的那个对象;构造函数调用,this指向实例的对象;使用window对象的方法使,指向window;多重场景改变this指向

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!