gpt4 book ai didi

javascript - javascript/jquery中的超简单动画引擎

转载 作者:行者123 更新时间:2023-11-30 05:52:43 24 4
gpt4 key购买 nike

我需要一个简单的引擎,告诉我所有已注册的动画完成后,何时动画(但也可以是ajax调用或具有某种“ onComplete”功能的任何东西)finsh。

我写了一个简单的jsFiddle

我有些怀疑:


 为什么我不能写this.ithis.finish但必须使用Engine.iEngine.finish?有没有更好的方法编写这样一个简单的类?我尝试记录一下here,但仍不清楚。 Engine内部的这个元素是一个div,因为它在$("#somediv").bind('click', function() { })内部被调用,但是我不知道在对象Engine上使用静态(??)变量是否是处理它的正确方法。感谢this的回答,我已经解决了“自我重复”问题(我怎么称呼这种方法?)
jQuery deferred object在这种情况下可以帮助我吗?也许有一种更简单,更有效的方法来与延迟对象一起编写它。我需要可以对任何内容(动画,预加载完成,ajax)进行调用的东西。


希望很清楚..任何建议或链接到类似情况的东西表示赞赏!

最后的代码

现在是最后一个代码:

engine = new Engine(); 

$("#clickme").bind('click', function() {
$(".bar").each(function() {
engine.add()
$(this).animate({width:200}, getRandomInt(500, 3000),
engine.oncomplete);
});
});

// animation engine
function Engine() {
var self = this;
this.i = 0;
this.add = function() {
self.i++;
}
this.oncomplete = function() {
self.i--;
if(self.i<=0){
self.finish();
}
}
this.finish = function() {
alert("done!");
}
}


最佳答案

更新:
我仔细看了看你的小提琴。需要修复一些问题。您正在定义构造函数中的所有方法。只是不要这样做:每次创建实例时,都会一次又一次地创建相同的函数。那只是完全的过度杀伤力。这是a working fiddle, where all methods are prototype properties

特别是其中一行导致了一些问题:

$(this).animate({width:200}, getRandomInt(500, 3000), engine.oncomplete);


在这里,您将对 oncomplete方法的引用作为回调传递,但是调用函数对象的上下文是临时确定的,因此不再引用实例 engine,但这是一个轻松解决:只需使用包装函数即可:

$(this).animate({width:200}, getRandomInt(500, 3000), function()
{//this anonymous function will get some context
engine.oncomplete();//but invokes oncomplete in the context of engine, this references engine here
});


一种替代方法是:一个闭包(像您一样,也许是在不知不觉中使用 var self创建的),它会覆盖原型方法:

engine.oncomplete = (function(that,prototypeMethod)
{//argument is reference to engine object, and the original method, that we're overriding
{
return function()
{//new version of the method, you can do this right after the instance is created
//or even in the constructor
return prototypeMethod.apply(that,[]);//call in correct context
};
}(engine,engine.oncomplete));
$(this).animate({width:200}, getRandomInt(500, 3000),engine.oncomplete);
delete engine.oncomplete;//reset to prototype method, optional


无论哪种方式,仅此而已。 Here's some more info on the matter - I think。还有一些事情可以调整,但总的来说,我认为您的工作进展顺利。请记住:最好使方法远离构造函数。如果第二个选项有点含糊(即IMO)。
我向自己保证,这将是我要添加到此答案的最后一个链接:我在 memory-leaks in JavaScript上问了一个问题,这是我的又一则又一则文章,但请看一看代码段:查看如何调用功能 reusableCallback,还查看我在自己的问题中发布的“答案”,这里有一个示例,说明了如何使用本机 prototypes。并且,如果您感到无聊或感兴趣,请尝试阅读代码并确定在任何给定时间 this将引用什么。如果您能解决问题,我可以公平地说您知道JS决定范围的基本原理。



您不能编写 this.finish,仅仅是因为 this没有名为 finish的属性。只是改变:

Engine.finish = function(){};




Engine.prototype.finish = function(){};


为什么?仅仅因为JS函数是一流的对象(无论如何它们都可以分配给变量,对函数对象的良好引用,它们可以作为参数传递给函数,它们可以作为函数的返回值等)...尝试 console.log(Engine instanceof Object);,它将记录为true。因此,您正在执行的操作是:

function Engine(){};
//is hoisted, and interpreted as:
var Engine = function(){};//<-- a function object, that is referenced by a var: Engine
Engine.finish = function(){};
//just like any object, assign a property to the object that Engine is referencing


但是,当您创建一个新的Engine对象时:

var myEngine = new Engine();


JS检查对象 Engine所引用的原型,在这种情况下,它引用一个函数。使用 new关键字调用该函数,因此JS将创建一个对象。为此,它需要原型(以及许多原型)。此特定函数(构造函数)的原型尚未定义任何属性,因此JS查找链中的下一个原型,即 Object原型。该原型的所有方法和属性都传递给新实例(尝试 myEngine.toString();Object.prototype.toString === myEngine.toString,您会注意到它们共享相同的方法)。
请注意,这并不是完全正确/准确的,甚至不是从构造函数创建新对象时正在发生的所有事情的10%,但这可能有助于您了解一些将来的事情。 :

假设您希望每个新实例都有一个 finish方法,并且-如您所知-所有新Engine实例都继承了 Object.prototype中的方法,您可能会这样做:

Object.prototype.finish = function(){};//!!


可以肯定,它将起作用,但是,然后: someArray.finish!是的,数组,功能,对DOM元素的引用以及您所拥有的都是对象。因此,请勿更改Object原型!
相反,JS允许您在原型级别上定义由该特定构造函数的所有实例共享的某些方法:

function Engine(){};//emtpy
Engine.prototype.i = 0;
var newEngine = new Engine();
console.log(newEngine.i);//0
var anotherEngine = newEngine();
newEngine.i = 1234;
console.log(anotherEngine.i);//0
console.log(newEngine.i);//1234


这将创建一个基本的原型链,如下所示:

EngineInstance {list of instance properties}
||
====>Engine.prototype {list of properties that all Engine instances have}
||
====> Object.prototype {properties for all objects, Engine is an object, so it should have these, too}


因此,无论何时创建新实例,都会为该新实例分配原型中定义的任何属性。因此,一个方法只能创建一次(而不是在构造函数内部创建,该构造函数将为每个实例创建一个新函数),并且所有实例将共享该方法。 but refer to MDN for more details

只需一件事情:JS以与创建对象相同的方式访问对象属性,除了顺序相反:
调用 newEngine.finish时,JS首先将查看该实例是否具有自己的 finish属性,如果没有,将检查 Engine原型,如果该原型也不具有finish方法,则JS将继续进行操作。原型链,直到找到所需的属性(一直到 Object.prototype为止),或者,如果对象原型不具有该属性,则它只会返回 undefined,说明一切,确实:此属性是 undefined

为此,您可以掩盖原型方法/属性,只要您需要它们的行为不同于默认行为即可,然后,只需 delete修改后的方法即可。这是一个真实的例子:

function doAjax(data, url, method)
{
var xhr = makeAjaxInstance();
data.toString = function()
{
return JSON.stringify(this);
};
//some more stuff, but then:
xhr.send(data + '');//<-- add empty string forces implicit call to the toString method
delete data.toString;
}
doAjax('my/url',{foo:'bar'},'post');


JS执行其通常的例程:检查 toString方法的实例,然后找到它。调用该函数,并发送一个整洁的JSON字符串。之后,将删除 toString方法。
JS在实例本身上搜索该属性。该方法被删除,因此原型的toString方法不再被屏蔽,在下次调用时,JS将执行相同的技巧,但是代替在 data上找到方法,它将扫描原型和常规服务恢复。我确实希望这个答案不会太混乱,但是我很累,所以如果这样:对不起

关于javascript - javascript/jquery中的超简单动画引擎,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13723027/

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