以下是我编写的用于管理canvas元素上的平板电脑手势的一些代码的简化代码段
首先是一个函数,它接受一个元素和一个回调字典并注册事件,并添加其他功能,如'hold'手势:
function registerStageGestures(stage, callbacks, recieverArg) {
stage.inhold = false;
stage.timer = null;
var touchduration = 1000;
var reciever = recieverArg || window;
stage.onLongTouch = function(e) {
if (stage.timer) clearTimeout(stage.timer);
stage.inhold = true;
if (callbacks.touchholdstart) callbacks.touchholdstart.call(reciever, e);
};
stage.getContent().addEventListener('touchstart', function(e) {
e.preventDefault();
calcTouchEventData(e);
stage.timer = setTimeout(function() {
stage.onLongTouch(e);
}, touchduration);
if (callbacks.touchstart) callbacks.touchholdstart.call(reciever, e);
});
stage.getContent().addEventListener('touchmove', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdmove) callbacks.touchholdmove.call(reciever, e);
} else {
if (callbacks.touchmove) callbacks.touchmove.call(reciever, e);
}
});
stage.getContent().addEventListener('touchend', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdend) callbacks.touchholdend.call(reciever, e);
} else {
if (callbacks.touchend) callbacks.touchend.call(reciever, e);
}
stage.inhold = false;
});
}
稍后我在同一页面中的几个元素(由'View'对象表示)上调用registerStageGestures。类似的东西:
function View() {
var self=this;
..
function InitView() {
...
registerStageGestures(kineticStage, {
touchstart: function(e) {
// do something
},
touchmove: function(e) {
// do something
},
touchendunction(e) {
// do something
},
touchholdstart: function(e) {
// do something
},
touchholdmove: function(e) {
// do something
},
touchholdend: function(e) {
// do something
},
}, self);
一切正常,但是我对在registerStageGestures的实现中有两件事感到疑惑:
首先,是否有必要让舞台上的inbut,timer和onLongTouch成员?或者如果它们是registerStageGestures中的本地变量,闭包会使一切正常吗?
其次,是否有必要使用'.call(接收器,'语法?)调用回调函数?我这样做是为了确保回调代码将在View的上下文中运行,但我不确定是否需要?
非常感谢任何输入
谢谢!
答案 0 :(得分:1)
这里有一些简单的答案。
首先,关闭:
Closure基本上表示无论在函数内部 中定义了什么,都可以访问该函数内容的其余部分。
所有这些内容都保证保持活着(在垃圾箱外),直到没有剩下的物品,这些物品在里面被创造出来。
一个简单的测试:
var testClosure = function () {
var name = "Bob",
recallName = function () { return name; };
return { getName : recallName };
};
var test = testClosure();
console.log(test.getName()); // Bob
因此,内部创建的任何内容都可以被也创建的任何函数访问(或者在函数[,...]中创建的函数内部创建)。
var closure_2x = function () {
var name = "Bob",
innerScope = function () {
console.log(name);
return function () {
console.log("Still " + name);
}
};
return innerScope;
};
var inner_func = closure_2x();
var even_deeper = inner_func(); // "Bob"
even_deeper(); // "Still Bob"
这不仅适用于内部创建的变量/对象/函数,也适用于内部传递的函数参数。
参数无法访问内部工作(除非传递给方法/回调),但内部工作将记住参数。
因此,只要您的函数在与您的值(或子范围)相同的范围内创建,就可以访问。
.call
比较棘手。
你知道它的作用(用你传递的对象替换函数内部的this
)...
......但为什么以及何时,在这种情况下更难。
var Person = function (name, age) {
this.age = age;
this.getAge = function () {
return this.age;
};
};
var bob = new Person("Bob", 32);
这看起来很正常 老实说,这可能看起来很像Java或C#,但有一些调整。
bob.getAge(); // 32
也像Java或C#一样工作。
doSomething.then(bob.getAge);
?嗯?
我们现在已经将Bob的方法作为一个函数单独传递给函数。
var doug = { age : 28 };
doug.getAge = bob.getAge;
现在我们已经给doug
一个直接使用bob
s methid的引用 - 不是副本,而是指向实际方法的指针。
doug.getAge(); // 28
嗯,这很奇怪。
作为回调传递出来的是什么?
var test = bob.getAge;
test(); // undefined
正如你所说,其原因在于背景......
但具体原因是因为JS中的函数内的this
没有预编译或存储...
每次调用函数时,this
都会动态计算出来。
如果你打电话
obj.method();
this === obj;
如果你打电话
a.b.c.d();
this === a.b.c;
如果你打电话
var test = bob.getAge;
test();
...
this
等于window
在“严格模式”中,这不会发生(你很快就会得到错误)。
test.call(bob); //32
恢复平衡!
...大多
仍然有一些捕获。
var outerScope = function () {
console.log(this.age);
var inner = function () {
console.log("Still " + this.age);
};
inner();
};
outerScope.call(bob);
// "32"
// "Still undefined"
当你想到它时,这是有道理的......
我们知道如果一个函数在被调用的时刻计算出this
- 范围与它无关......
...我们没有将inner
添加到对象...
this.inner = inner;
this.inner();
会工作得很好(但现在你只是搞砸了一个外部对象)......
因此inner
将this
视为window
。
解决方案是使用.call
,或.apply
,或 使用函数范围和/或关闭
var person = this,
inner = function () { console.log(person.age); };
兔子洞越来越深,但我的手机正在死...
答案 1 :(得分:1)
首先,是否需要保留,计时器和onLongTouch成员 舞台?或者闭包会使一切运转良好 registerStageGestures中的本地变量?
就registerStageGestures()
而言,var inhold
,var timer
和function onLongTouch(e) {...}
。就够了内部函数自动访问其外部函数成员的机制称为“闭包”。如果其他一些代码需要访问这些设置作为stage.inhold
的属性,您只需要设置stage.timer
,stage.onLongTouch
和stage
。
其次,是否有必要使用'.call(receiver,')调用回调函数。 句法 ?我这样做是为了确保回调代码将在 视图的上下文,但我不确定是否需要它?
可能,取决于这些回调的编写方式。在内部调用使用.call()
的函数时,有时会使用.apply()
和this
。在这两种情况下,传递的第一个参数定义要解释为this
的对象。因此,javascript为您提供了定义通用方法的方法,没有先验关于调用这些方法时将应用的对象的假设。类似地,您可以调用对象的方法,使其作用于另一个对象。
修改强>
为了完整性,请注意即使函数中没有this
,.apply()
也非常有用,因为它允许将多个参数指定为单个数组的元素,例如无处不在jQuery.when.apply(null, arrayOfPromises)...