前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Javascript中的this指向

Javascript中的this指向

原创
作者头像
超级大帅比
修改2021-09-13 11:26:56
8830
修改2021-09-13 11:26:56
举报
文章被收录于专栏:长路漫漫长路漫漫

1 全局环境下

在全局环境下,this 始终指向全局对象(window), 无论是否严格模式

console.log(this.document === document); // true

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

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

2 函数上下文中

2.1 函数直接调用

非严格模式下,this 默认指向全局对象window;

严格模式下, this为undefined;

function f1(){
  return this;
}

f1() === window; // true

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

f2() === undefined; // true

2.2 对象内部方法中的this

this指向只和调用函数的对象有关;

多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象, 而非window);

function independent() {
  return this.prop;
}

var o = {
  prop: 37,
  f: independent
};
console.log(o.f());  //37
var a = o.f;
console.log(a()):  //undefined

o.b = {
  g: independent,
  prop: 42
};
// 嵌套调用
console.log(o.b.g()); // logs 42

2.3 原型链中方法的this

原型链中的方法的this仍然指向调用它的对象;

var o = {
  f : function(){ 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

2.4 getter 与 setter 中的 this

用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象;

function sum() {
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average() {
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(o, 'sum', {
    get: sum, enumerable: true, configurable: true});

console.log(o.average, o.sum); // logs 2, 6

2.5 构造函数中this

构造函数中的this与被创建的新对象绑定;

(当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this)

function C(){
  this.a = 37;
  console.log(this.a)
}

var c  = new C() // 37

2.6 类上下文中的this

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

类的构造函数中,this 是一个常规对象,与构造函数的this一样;

类中所有非静态的方法都会被添加到 this 的原型中;

(静态方法不是 this 的属性,它们只是类自身的属性。)

如果是派生类,使用this时需要先在构造函数中调用 super(参数)生成一个 this 绑定;

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

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

2.7 DOM事件处理函数中的this

事件源.onclik = function(){ } this指向事件源

事件源.addEventListener(function(){ }) //this指向事件源

var div = document.getElementById('divId');
div.addEventListener('click', function () {
    console.log(this); // div
}, false);
div.onclick = function() {
    console.log(this); // div
}

2.8 内联事件中的this

当this传入内联处理函数时,它的this指向监听器所在的DOM元素;

当this没有传入内联处理函数时,其this指向等同于 函数直接调用的情况,即在非严格模式指向全局对象window, 在严格模式指向undefined;

<button onclick="console.log(this);" /> // button
<button onclick="(function() { console.log(this); })();" /> // window
<button onclick="(function() { 'use strict' console.log(this); })();" /> // undefined

2.9 setTimeout 和 setInterval中的普通函数this

setTimeout 和 setInterval中的普通函数this指向全局对象window;

(如果传入的函数已绑定this或者是箭头函数,则不适用这条,需要继续往下看)

function Person() {  
    this.age = 0;  
    setTimeout(function() {
        console.log(this);
    }, 3000);
}
var p = new Person();//3秒后返回 window 对象

2.10 箭头函数中的 this

箭头函数不绑定this, 它会捕获其所在(即定义的位置)上下文的this值, 作为自己的this值;

function Person() {  
    this.age = 0;  
    setInterval(() => {
        // 回调里面的 `this` 变量就指向了期望的那个对象了
        this.age++;
    }, 3000);
}

var p = new Person();

2.11 嵌套函数中的this

this在嵌套函数中不会传递,即直接调用与普通函数一样,非严格模式下为window,严格模式下为undefined;

var obj = {
    A: function() {
        function B() {
            console.log(this);
        };
        B(); // window
        function C() {
            'use strict'
            console.log(this);
        }
        C(); // undefined
    }
}

3 修改this的指向(call、apply、bind)

这三个函数都在Function的原型链上(Function.prototype),函数对象可以直接调用;

非严格模式下第一个参数为null或undefined时,this为window,原始值会被包装;

严格模式下this就是传入的值;

3.1 call、apply函数

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

console.log(new Food('cheese', 5).name);
// expected output: "cheese"

apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。

var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]

3.2 bind函数

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

const obj1 = {
    a: 1,
    getA: function() {
        return this.a;
    },
    sum: function(x, y) {
        return this.a + x + y;
    }
}
const obj2 = { a: 2 };
const obj2GetA = obj1.getA.bind(obj2);
obj2GetA(); //
const sum2 = obj1.sum.bind(obj2, 2);
sum2(2); // 2 + 2 + 2 = 6

// 如果绑定后的函数使用new来调用,原来提供的 this 就会被忽略。
// 作为构造函数使用的绑定函数,可能不应该用在任何生产环境中。

// bind的一个简单实现
if (!Function.prototype.bind) (function(){
  var ArrayPrototypeSlice = Array.prototype.slice;
  Function.prototype.bind = function(otherThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var baseArgs= ArrayPrototypeSlice.call(arguments, 1),
        baseArgsLength = baseArgs.length,
        // fToBind是调用bind的函数本身
        fToBind = this,
        // 绑定后的函数用new调用时,用来作为生成对象的原型的构造函数
        fNOP    = function() {},
        // 最终绑定的函数
        fBound  = function() {
          baseArgs.length = baseArgsLength; // reset to default base arguments
          baseArgs.push.apply(baseArgs, arguments);
          // 下面的this是fBound执行时的this,如果fBound使用new调用,则使用生成对象的作为this
          return fToBind.apply(
                 fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs
          );
        };

    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
})();

参考

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/call

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

https://www.cnblogs.com/dongcanliang/p/7054176.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 全局环境下
  • 2 函数上下文中
    • 2.1 函数直接调用
      • 2.2 对象内部方法中的this
        • 2.3 原型链中方法的this
          • 2.4 getter 与 setter 中的 this
            • 2.5 构造函数中this
              • 2.6 类上下文中的this
                • 2.7 DOM事件处理函数中的this
                  • 2.8 内联事件中的this
                    • 2.9 setTimeout 和 setInterval中的普通函数this
                      • 2.10 箭头函数中的 this
                        • 2.11 嵌套函数中的this
                        • 3 修改this的指向(call、apply、bind)
                          • 3.1 call、apply函数
                            • 3.2 bind函数
                            • 参考
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档