Javascript scope and self=this, _this=this, that=this

Javascript scope and self=this, _this=this, that=this

本文关键字:this that scope self Javascript and      更新时间:2023-09-26

为什么_this.不工作,但this.正在工作。

我认为_this=this的全部意义在于为调用对象函数提供一种机制,您有一个"保证"的引用,回到实例化的对象,因为它现在在对象函数的闭包中模仿传统的类行为。 我读了很多关于范围的文章,但由于某种原因,我只是没有看到它。 我错过了什么?

var PersonClass = function PersonClass(_name, _age) {
    _this=this;
    this.name=_name;
    this.age=_age;
    console.log("created "+this.name+":"+this.age);
    function changeAge(num) {
        console.log("changing age for:" + _this.name);
        _this.age=num;
    }
    PersonClass.prototype.changeAge=changeAge;
    PersonClass.prototype.getAge=function() { 
        console.log(_this.name+":"+_this.age);
        return _this.age;
    };
    PersonClass.prototype.getAge2=function() { 
        console.log(this.name+":"+this.age);        
        return this.age;
    };
};
// comments indicate what value is displayed in console
var john=new PersonClass("john",1);  // john:1
var sue=new PersonClass("sue",2);    // sue:2
john.getAge(); // sue:2
john.getAge2(); // john:1
john.changeAge(10); // sue
sue.getAge(); // sue:10
sue.getAge2(); // sue:10
john.getAge(); // sue:10
john.getAge2(); // john:1

问题是您的内部函数的scope没有被解析为this,因此,它们失去了对在new PersonClass()实例化时创建的作用域的所有引用。bind 方法会将内部函数的scope解析为父函数类的this

var PersonClass = function PersonClass(_name, _age)
{
    var _this=this;
    this.name=_name;
    this.age=_age;
    console.log("created "+this.name+":"+this.age);
    this.changeAge = function(num)
    {
        console.log("changing age for:" + _this.name);
        _this.age = num;
    }.bind(this);
    this.getAge = function()
    { 
        console.log(_this.name+":"+_this.age);
        return _this.age;
    }.bind(this);
    this.getAge2 = function()
    { 
        console.log(this.name+":"+this.age);        
        return this.age;
    };
};
// comments indicate what value is displayed in console
var john = new PersonClass("john",1);  // john:1
var sue = new PersonClass("sue",2);    // sue:2
john.getAge(); // sue:2
john.getAge2(); // john:1
john.changeAge(10); // sue
sue.getAge(); // sue:10
sue.getAge2(); // sue:10
john.getAge(); // sue:10
john.getAge2(); // john:1

是的,那就行了。

嘿,看,它有效!这是更新的小提琴

只是为了提供有关bind的更多信息

假设我有一个object

var myObj = {};

我们为该object分配一个属性:

myObj.test_property = "Hello World!";

我们可以通过其他属性访问该属性 bindthis .

假设我们制作另一个属性,它是一个function

myObj.test_func = function()
{
    alert(this.test_property);
}.bind(myObj);

等等,你猜这样行吗?

由于bind方法,this的范围被解析为myObj

因此,this.test_property等于 myObj.test_property ,保留范围。

让我们更进一步...

我们将声明另一个函数:

myObj.test_func2 = function(val)
{
    this.test_property = val;
}.bind(myObj);

现在,让我们运行一个测试:

myObj.test_func();
myObj.test_func2("Hello Dude");
myObj.test_func();

如您所见,test_functest_func2共享相同的范围。

这是一个JSFiddle,说明了我所说的关于bind的所有内容

当你打电话时

new PersonClass()

第一次,创建原型方法。

当您致电时

new PersonClass()

第二次,原型方法被替换,现在它们在闭合范围内具有最后一个_this

因此,将原型方法移到构造函数之外。

你的代码有很多问题。

  1. _this=this;

    创建全局变量window._this 。 使用像jshint这样的工具来避免这种错误。

  2. PersonClass.prototype不应在构造函数中使用。您正在混合两种不同的对象创建模式。在构造函数中,您应该使用类似的东西

    this.getAge2 = function(){...}

  3. 不一定是错误,但对于您的示例代码,不需要将其绑定到_this。仅当函数未在您创建的对象上调用时,才会使用此功能,例如,使用 window.setTimeout(john.getAge, 100)

    这会导致 getAge 函数在调用时与 john 对象解除绑定。

这是包含所讨论更改的代码(这并不是说我推荐这种模式):

var PersonClass = function PersonClass(_name, _age) {
    var _this=this;
    this.name=_name;
    this.age=_age;
    console.log("created "+this.name+":"+this.age);
    function changeAge(num) {
        console.log("changing age for:" + _this.name);
        _this.age=num;
    }
    this.changeAge=changeAge;
    this.getAge=function() { 
        console.log(_this.name+":"+_this.age);
        return _this.age;
    };
    this.getAge2=function() { 
        console.log(this.name+":"+this.age);        
        return this.age;
    };
};

var john=new PersonClass("john",1);  // john:1
var sue=new PersonClass("sue",2);    // sue:2
john.getAge(); // john:1
john.getAge2(); // john:1
john.changeAge(10); // john
sue.getAge(); // sue:2
sue.getAge2(); // sue:2
john.getAge(); // john:10
john.getAge2(); // john:10

window.setTimeout(john.getAge, 200); //john:10
window.setTimeout(john.getAge2, 400); // incorrect