Javascript 如何在回调中访问正确的'this'?

Javascript 如何在回调中访问正确的'this'?,javascript,callback,this,Javascript,Callback,This,我有一个注册事件处理程序的构造函数: 函数MyConstructor(数据、传输){ 这个数据=数据; transport.on('data',function(){ 警报(此数据); }); } //模拟传输对象 var传输={ on:函数(事件、回调){ setTimeout(回调,1000); } }; //称为 var obj=新的MyConstructor('foo',transport)关于此 此(又称“上下文”)是每个函数中的一个特殊关键字,其值仅取决于函数的调用方式,而不是函数

我有一个注册事件处理程序的构造函数:

函数MyConstructor(数据、传输){
这个数据=数据;
transport.on('data',function(){
警报(此数据);
});
}
//模拟传输对象
var传输={
on:函数(事件、回调){
setTimeout(回调,1000);
}
};
//称为
var obj=新的MyConstructor('foo',transport)关于
(又称“上下文”)是每个函数中的一个特殊关键字,其值仅取决于函数的调用方式,而不是函数的定义方式/时间/地点。与其他变量一样,它不受词法范围的影响(箭头函数除外,见下文)。以下是一些例子:

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

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
要了解有关此
的更多信息,请查看


如何引用正确的

使用
ECMAScript 6引入了箭头函数,可以将其视为lambda函数。他们没有自己的
绑定。相反,
这个
像普通变量一样在范围内查找。这意味着您不必调用
.bind
。这不是他们唯一的特殊行为,更多信息请参考MDN文档

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}
不要使用
实际上,您不想访问此
,尤其是它所指的对象。这就是为什么一个简单的解决方案是创建一个新的变量,该变量也引用该对象。变量可以有任何名称,但常见的名称是
self
that

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}
由于
self
是一个普通变量,因此它遵守词法范围规则,并且可以在回调中访问。这还有一个优点,即您可以访问回调本身的
This

显式设置回调的
-第1部分 您可能无法控制此
的值,因为它的值是自动设置的,但事实并非如此

每个函数都有一个方法,该方法返回一个新函数,并将
this
绑定到一个值。该函数的行为与您调用的
.bind
on函数完全相同,只是
由您设置。无论如何或何时调用该函数,
将始终引用传递的值

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}
第一个参数是回调,第二个参数是这个
应该引用的值。下面是一个人为的例子:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
函数
this.method
被指定为click事件处理程序,但如果单击
document.body
,则记录的值将
未定义
,因为在事件处理程序中,
指的是
document.body
,而不是
Foo
的实例
如前所述,此所指的内容取决于函数的调用方式,而不是定义方式 如果代码如下所示,则函数没有对对象的隐式引用可能更为明显:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;
解决方案与上述相同:如果可用,请使用
.bind
显式绑定到特定值

document.body.onclick = this.method.bind(this);
或者使用匿名函数作为回调/事件处理程序显式调用函数作为对象的“方法”,并将对象(
this
)分配给另一个变量:

var self = this;
document.body.onclick = function() {
    self.method();
};
或使用箭头功能:

document.body.onclick = () => this.method();
this.saveNextLevelData(this.setAll.bind(this));
这都是调用方法的“神奇”语法:

object.property();
当您从对象获取属性并一次性调用它时,该对象将成为该方法的上下文。如果调用相同的方法,但在不同的步骤中,则上下文是全局范围(窗口):

当您获得方法的引用时,它不再附加到对象,它只是对普通函数的引用。当获取要用作回调的引用时,也会发生同样的情况:

this.saveNextLevelData(this.setAll);
这就是将上下文绑定到函数的位置:

document.body.onclick = () => this.method();
this.saveNextLevelData(this.setAll.bind(this));
如果使用jQuery,则应使用
$.proxy
方法,因为并非所有浏览器都支持
bind

this.saveNextLevelData($.proxy(this.setAll, this));
“语境”的麻烦 术语“上下文”有时指的是本文档引用的对象。它的使用是不恰当的,因为它在语义上或技术上都不适合

意思是指围绕某事物而增加意义的环境,或是一些赋予额外意义的前后信息。术语“context”在ECMAScript中用来指代,它是一些执行代码范围内的所有参数和范围

如图所示:

将ThisBinding设置为与的ThisBinding相同的值 调用执行上下文

这清楚地表明这是执行上下文的一部分

执行上下文提供周围信息,为正在执行的代码添加意义。它所包含的信息远不止这些

所以它的价值不是“上下文”,它只是执行上下文的一部分。它本质上是一个局部变量,可以通过调用任何对象并在严格模式下设置为任何值。

以下是在子上下文中访问父上下文的几种方法-
  • 您可以使用
    ()
    函数
  • 将对context/this的引用存储在另一个变量中(参见下面的示例)
  • 使用ES6功能
  • 改变代码/功能设计/架构-为此,您应该拥有javascript中的命令
  • 1.使用
    bind()
    函数
    函数MyConstructor(数据、传输){
    这个数据=数据;
    transport.on('data',(function)(){
    警报(此数据);
    }).约束(这个);
    }
    //模拟传输对象
    var传输={
    on:函数(事件、回调){
    setTimeout(回调,1000);
    }
    };
    //称为
    var obj=新M
    
    this.saveNextLevelData($.proxy(this.setAll, this));
    
    transport.on('data', _.bind(function () {
        alert(this.data);
    }, this));
    
    there are two types of scope in javascript. They are :
    
       1) Global Scope
    
       2) Function Scope
    
    --------------------------------------------------------------------------------
    -                                                                              -
    -   Global Scope                                                               -
    -   ( globally "this" refers to window object)                                 -     
    -                                                                              -
    -         function outer_function(callback){                                   -
    -                                                                              -
    -               // outer function scope                                        -
    -               // inside outer function"this" keyword refers to window object -                                                                              -
    -              callback() // "this" inside callback also refers window object  -
    
    -         }                                                                    -
    -                                                                              -
    -         function callback_function(){                                        -
    -                                                                              -
    -                //  function to be passed as callback                         -
    -                                                                              -
    -                // here "THIS" refers to window object also                   -
    -                                                                              -
    -         }                                                                    -
    -                                                                              -
    -         outer_function(callback_function)                                    -
    -         // invoke with callback                                              -
    --------------------------------------------------------------------------------
    
    function Person(name){
    
        this.name = name
    
        this.sayNameVersion1 = function(callback){
            callback.bind(this)()
        }
        this.sayNameVersion2 = function(callback){
            callback()
        }
    
        this.sayNameVersion3 = function(callback){
            callback.call(this)
        }
    
        this.sayNameVersion4 = function(callback){
            callback.apply(this)
        }
    
    }
    
    function niceCallback(){
    
        // function to be used as callback
    
        var parentObject = this
    
        console.log(parentObject)
    
    }
    
    var p1 = new Person('zami') // create an instance of Person constructor
    
    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }
    
    p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
    
    p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
    
    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }
    
    p1.sayNameVersion3(niceCallback)
    
    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }
    
    p1.sayNameVersion4(niceCallback)
    
    setTimeout(function(){
        this.methodName();
    }.bind(this), 2000);
    
    var obj = {
      handleEvent(e) {
        // always true
        console.log(this === obj);
      }
    };
    
    document.body.addEventListener('click', obj);
    
    class someView {
        onSomeInputKeyUp = (event) => {
            console.log(this); // this refers to correct value
        // ....
        someInitMethod() {
            //...
            someInput.addEventListener('input', this.onSomeInputKeyUp)
    
    function MyConstructor(data, transport) {
        this.data = data;
        var self = this;
        transport.on('data', function () {
            alert(self.data);
        });
    }
    
      function MyConstructor(data, transport) {
        this.data = data;
        transport.on('data',()=> {
            alert(this.data);
        });
    }
    
      function MyConstructor(data, transport) {
        this.data = data;
        transport.on('data',(function() {
            alert(this.data);
        }).bind(this);
    
    function MyConstructor(data, transport) {
      this.data = data;
      transport.on('data', () => {
        alert(this.data);
      });
    }
    
    module.exports.data = 'module data';
    // This outside a function in node refers to module.exports object
    console.log(this);
    
    const obj1 = {
        data: "obj1 data",
        met1: function () {
            console.log(this.data);
        },
        met2: () => {
            console.log(this.data);
        },
    };
    
    const obj2 = {
        data: "obj2 data",
        test1: function () {
            console.log(this.data);
        },
        test2: function () {
            console.log(this.data);
        }.bind(obj1),
        test3: obj1.met1,
        test4: obj1.met2,
    };
    
    obj2.test1();
    obj2.test2();
    obj2.test3();
    obj2.test4();
    obj1.met1.call(obj2);
    
    xFormat (value): string {
      return value.toString() + this.oneComponentVariable; //gives wrong result 
    }
    
     xFormat = (value) => {
       // console.log(this);
       // now you have access to your component variables
       return value + this.oneComponentVariable
     }