有没有办法在JavaScript中修改'this'?

时间:2015-10-15 16:04:17

标签: javascript

我找到了这个答案:How to modify "this" in javascript

但我不喜欢它。肯定有办法以某种方式修改this

以下是一个例子:

(function()
{

    var a = function(v)
    {
        v += 10;

        a = function()
        {
            console.log(this);
            this += 5; // How to "unlock" 'this'?
            console.log(this);
        }.bind(v)

        //a();
    }

    a(0);
    a();

})();

小提琴:https://jsfiddle.net/ahvonenj/mz19aku6/

如果您注释掉this += 5部分,则控制台会说thisNumber {[[PrimitiveValue]]: 10}。所以我没有看到为什么Number(PrimitiveValue)类型不能增加5并打印出来的原因。我在这里缺少什么?

有没有办法“突破”引擎,将this视为this并以某种方式强行将this转换为它所说的内容 - Number案件?

也许通过某种方式创建一个接受to-be-converted this作为参数的函数并返回一个新函数,其中this反弹bind

注意:我不是在寻找可行的解决方案。我只是从技术角度或其他方面感到好奇。

编辑:所以名为Oriol的用户告诉我,this实际上并不是一个值为10的Number对象,而是一个数字文字。这显然意味着this += 5几乎与在这种情况下编写10 += 5相同。我试着像这样退房:

(function()
{

    var a = function(v)
    {
        v += 10;

        a = function()
        {
            console.log(this);
            var p = this + 5; // How to "unlock" 'this'?
            console.log(p);
        }.bind(v)

        //a();
    }

    a(0);
    a();

})();

所以var p = this + 5现在与编写var p = 10 + 5基本相同,这正是我们所期望的。

4 个答案:

答案 0 :(得分:3)

您可以将this视为伴随函数调用的隐式不可变值。

可以设置多种方式,最常见的是o.f()形式的调用将this设置为o f。当然,this也可以设置为callapply以及bind,也可以通过其他方式设置。

this与其他函数参数不同。如果是正常参数,理论上可以更改其值。相反,它代表,这是this值的一种词汇占位符。换句话说,如果我打电话

f.call(5)

然后写

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

你可以认为this词汇替换为值5.所以如果我试着写

function() { this += 5; }

你可以认为这相当于

function() { 5 += 5; }

这显然是胡说八道。我不能用其他东西替换值5。出于同样的原因,如果我说

o = {
  f: function() { this = o2; }
};

然后调用o.f(),该函数基本上被重写为

function() { { f: ... } = o2; }

这是胡说八道。我无法重新分配对象的值。

由于this是值,而不是参数,因此无法将其分配或更改。对于作业而言,它不是有效的左侧,不仅仅是42。我们无法更改名为42的值的值。我们无法更改名为this的值的值。

原因是规格。从理论上讲,人们可以想象this 可变的JavaScript版本。没有明确的理由说明为什么这是不可能的。毕竟,无论它来自哪里,在函数中它只是一个值。这会让人感到困惑,并可能导致意外行为,但没有理由说它无法正常工作。

不支持这一主要原因仅仅是语言的定义方式。如果您的问题是"为什么语言以这种方式定义",那么语言历史学家就可以回答这个问题。但是,人们可以想象这很好的理由,涉及直观的代码行为。

请考虑以下代码:

o = {
  f: function() { 
    this.doSomething();
    this = o2;
    this.doSomething();
};

普通人很难理解这些代码。由于对this.doSomething()的干预性更改,相同的两个this调用会执行两个不同的操作。仅这一点就是禁止改变this值的充分理由。更是如此,因为没有合理的理由需要这样做,因为我可以用简单的o2.doSomething()替换最后两行。

当然,当我们谈论"改变this"时,即使我们可以做到这一点,我们无法做到,我们也无法做到这一点。可能意味着以某种方式改变外部值this指的是。我们都知道在以下情况中:

function a(x) { x = 2; }
var y = 1;
a(y);

xa()的更改纯属本地化,可能不会影响y。同样的事情同样适用于this

关于包裹基元的对象的另一个注释。我们知道我们可以写

o5 = Object(5);

获取一个包装数字5的对象。现在我可以在这个对象上定义一个方法,如

o5.f = function() { console.log(this); };

并且调用o5.f()将记录

Number {[[PrimitiveValue]]: 5}

因此,这个对象"是"一个数字,当然在这种情况下我应该可以说

o5.f = function() { this++; };

但不是。 this不是数字5;它是一个物体包装物5.这是两个非常不同的东西。上面的函数基本上等于说

o5.f = function() { Object(5)++; }

产生

Uncaught ReferenceError: Invalid left-hand side expression in postfix operation

现在我可以对该对象进行算术运算,例如Object(5) + 1,因为JS会在添加对象之前将对象强制转换为其基础原语。但我不能再为这个对象重新分配任何其他对象了。我无法修改对象底层的原始数字。创建包装器对象后,其基础的原始值将永久锁定。

所以问题的答案是"不,没有办法改变this"。这并不是说没有其他方法可以做其他事情来完成你想要完成的任何事情。

答案 1 :(得分:2)

实际上这里的问题是当你将函数绑定到一个数字时,this会变为数字,现在当你进行赋值操作this += 5;时,左边不是变量,我们可以将新值存储为原始数字实例。所以要克服你可以做的是你可以将这个值存储在另一个变量me中,然后执行如下操作:

(function() {

    var a = function(v) {
        v += 10;

        a = function() {
            var me = this;
            console.log(this); //logs Number {[[PrimitiveValue]]: 10}
            me += 5; 
            console.log(me); //logs 15
        }.bind(v)

        //a();
    }

    a(0);
    a();

})();

答案 2 :(得分:2)

我不知道任何允许您更改this语言。

您可能希望将this视为地址:
我的房子“坐”在芝麻街10号。当然,我可以邀请那些可以改变我的芝麻街10号房子的设计师,但是我可以突然让芝麻街10号变成芝麻街15号吗?当然不是。我不能只撕掉整块土地,然后将5个房子传给前方。

返回编程上下文,this(最终)被解释为对象所在的内存块。您可以更改位于指定内存块上的对象,但不能只更改块地址。

答案 3 :(得分:1)

请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures

简单类型(对象和数组除外)是不可变的。您无法修改它并保存在源变量中。

function foo() {
    this.val+=10;
}

a=function(obj) {
    a=foo.bind(obj);
}

但你可以把它包装成对象。请参阅:http://jsfiddle.net/5dhm8fsn/