gpt4 book ai didi

JavaScript 闭包和 "this"

转载 作者:行者123 更新时间:2023-12-02 19:11:49 25 4
gpt4 key购买 nike

我的问题是...在 TestObj 的 CallMeLaterTestObj 函数中,“this”是窗口对象,而不是 TestObj。我如何重构它,以便在 CallMeLater 函数中我不必包装 call function() { v.CallMeLaterTestObj(); } 在闭包中或使用绑定(bind)函数,因为它对较新浏览器的支持有限。两个目标:

  • 在对象内的函数调用中保留“this”
  • 为每个单独的对象维护一个单独的“value”值,这样它们就不会共享相同的值。

    //模拟公共(public) api、私有(private)方法、私有(private)变量、公共(public)字段。

    //问题的新部分

  • 重写以包括绑定(bind)函数和原型(prototype)符号。如何将 Binding 函数移至所有新对象都会获得的基础对象中?

  • 这已经是我能做到的最接近两全其美的了。我不知道这种方法有什么陷阱

        var BaseObject = function ()
    {
    _getBinding = function (method)
    {
    var _self = this;
    return function ()
    {
    _self[method].apply(_self, arguments);
    };
    };
    return {
    CallInline: _getBinding
    }
    }();


    var TestObj = function (value)
    {
    $.extend(this, BaseObject);
    // public var
    this._value = value;
    };

    TestObj.prototype = function()
    {
    var privateVar = false;
    // these are private
    _giveMe = function () {
    return this._value;
    },
    _callMeLaterTestObj = function () {
    console.log('I am ' + this.constructor.name + ' my value is ' + this._value);
    };

    // public API
    return {
    GiveMe : _giveMe,
    CallMeLaterTestObj : _callMeLaterTestObj
    }

    }();

    function CallMeLater(v, i)
    {
    setTimeout(v.CallInline('CallMeLaterTestObj'), 10);
    }



    var V1 = new TestObj(1);
    var V2 = new TestObj(2);
    var V3 = new TestObj(3);


    console.log('V1= ' + V1.GiveMe());
    console.log('V2= ' + V2.GiveMe());
    console.log('V3= ' + V3.GiveMe());
    console.log('---');

    V1.CallMeLaterTestObj();

    console.log('---');

最佳答案

我认为您正在寻找的是:

function TestObj(value) {
var _value = value;

this.giveMe = function() {
return _value;
};

this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};

return this;
};

function callMeLater(v, i) {
setTimeout(function() {
v.callMeLaterTestObj();
}, 10);
}

var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);

console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');

callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);​

要访问 constructor.name,您需要使用 function name() 语法声明该函数,而不是 var name = function() 语法。

要保留私有(private)变量并公开公共(public) API,请将公共(public)变量公开为函数中 this 的属性。

请务必从构造函数返回 this 以使其正常工作。

对于类名(TestObj 就是其中之一)遵循 CamelCase 命名约定,对于变量/方法/对象/等遵循小驼峰命名约定也是一种很好的做法。有助于明确哪些变量是实例,哪些是类.

Test and see the console output expected here .

注意

关于将 v.callMeLaterTestObj() 包装在 setTimeout 的闭包中,此技术完全跨浏览器兼容。您不会有任何问题。

bind 方法较新,尽管有许多库可以在旧版浏览器中为您填充该方法。我个人最喜欢的是underscore .

注2

如果不将对象包装在某处的闭包中,则无法在 setTimeout 中调用对象上的方法,但是如果您愿意,您可以在类中抽象闭包,而无需使用通用的 bind 函数(由 Underscore 或 jQuery 等提供)你可以在类中“推出你自己的”,如下所示:

function TestObj(value) {

var _value = value;
var _self = this;

this.giveMe = function() {
return _value;
};

this.callMeLaterTestObj = function() {
console.log('I am ' + this.constructor.name + ' my value is ' + _value);
};

this.getBinding = function(method) {
var _self = this;
return function() {
_self[method].apply(_self, arguments);
};
};

return this;
};

function callMeLater(v, i) {
setTimeout(v.getBinding('callMeLaterTestObj'), 10);
}

var v1 = new TestObj(1);
var v2 = new TestObj(2);
var v3 = new TestObj(3);

console.log('V1= ' + v1.giveMe());
console.log('V2= ' + v2.giveMe());
console.log('V3= ' + v3.giveMe());
console.log('---');

callMeLater(v1, 1);
callMeLater(v2, 2);
callMeLater(v3, 3);​

说明:

您需要使用某种类型的绑定(bind),因为当您将方法传递给setTimeout时,您是通过引用传递它的。因此,setTimeout 看到的只是一个函数,而不是它所在的对象,这就是为什么你会丢失 this 的上下文。

由于 setTimeout 将在默认范围(即浏览器窗口)中执行该函数,因此您需要一种方法来通过引用获取 this ,可以通过内联匿名函数,也可以通过返回使用 apply 方法“重置”this 的闭包。

注解3

如果您想拥有自己的绑定(bind)方法,并且不包含为您提供该方法的库或将其包含在每个类中,那么您可以使用 Underscore 中的这个方法,它遵循较新浏览器中的 native 方法:

function bind(func, context) {
var bound, args;
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
if (!_.isFunction(func)) throw new TypeError;
args = slice.call(arguments, 2);
return bound = function() {
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
ctor.prototype = func.prototype;
var self = new ctor;
var result = func.apply(self, args.concat(slice.call(arguments)));
if (Object(result) === result) return result;
return self;
};
};

然后像这样使用它:

function callMeLater(v, i) {
setTimeout(bind(v.callMeLaterTestObj, v), 10);
}

这在所有浏览器中都可以正常工作。

关于JavaScript 闭包和 "this",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13629127/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com