- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我开始研究 JS 的动态分析工具,我想不引人注意地分析整个环境。我基本上是在遍历各种上下文,深入研究对象,每次我遇到一个函数时,我都会 Hook 它。现在,除了在处理 jQuery/prototype 等库时它会中断之外,它工作得相对较好。
这是我到目前为止的代码(尽我所能评论):
var __PROFILER_global_props = new Array(); // visited properties
/**
* Hook into a function
* @name the name of the function
* @fn the reference to the function
* @parent the parent object
*/
function __PROFILER_hook(name, fn, parent) {
//console.log('hooking ' + name + ' ' + fn + ' ' + parent);
if (typeof parent == 'undefined')
parent = window;
for (var i in parent) {
// find the right function
if (parent[i] === fn) {
// hook into it
console.log('--> hooking ' + name);
parent[i] = function() {
console.log('called ' + name);
return fn.apply(parent, arguments);
}
//parent[i] = fn; // <-- this works (obviously)
break;
}
}
}
/**
* Traverse object recursively, looking for functions or objects
* @obj the object we're going into
* @parent the parent (used for keeping a breadcrumb)
*/
function __PROFILER_traverse(obj, parent) {
for (i in obj) {
// get the toString object type
var oo = Object.prototype.toString.call(obj[i]);
// if we're NOT an object Object or an object Function
if (oo != '[object Object]' && oo != '[object Function]') {
console.log("...skipping " + i);
// skip
// ... the reason we do this is because Functions can have sub-functions and sub-objects (just like Objects)
continue;
}
if (__PROFILER_global_props.indexOf(i) == -1 // first we want to make sure we haven't already visited this property
&& (i != '__PROFILER_global_props' // we want to make sure we're not descending infinitely
&& i != '__PROFILER_traverse' // or recusrively hooking into our own hooking functions
&& i != '__PROFILER_hook' // ...
&& i != 'Event' // Event tends to be called a lot, so just skip it
&& i != 'log' // using FireBug for debugging, so again, avoid hooking into the logging functions
&& i != 'notifyFirebug')) { // another firebug quirk, skip this as well
// log the element we're looking at
console.log(parent+'.'+i);
// push it.. it's going to end up looking like '__PROFILER_BASE_.something.somethingElse.foo'
__PROFILER_global_props.push(parent+'.'+i);
try {
// traverse the property recursively
__PROFILER_traverse(obj[i], parent+'.'+i);
// hook into it (this function does nothing if obj[i] is not a function)
__PROFILER_hook(i, obj[i], obj);
} catch (err) {
// most likely a security exception. we don't care about this.
}
} else {
// some debugging
console.log(i + ' already visited');
}
}
}
这就是配置文件,这就是我调用它的方式:
// traverse the window
__PROFILER_traverse(window, '__PROFILER_BASE_');
// testing this on jQuery.com
$("p.neat").addClass("ohmy").show("slow");
只要函数简单且非匿名,遍历和 Hook 就可以正常工作(我认为 Hook 到匿名函数是不可能的,所以我不太担心)。
这是预处理阶段的一些 trim 输出。
notifyFirebug already visited
...skipping firebug
...skipping userObjects
__PROFILER_BASE_.loadFirebugConsole
--> hooking loadFirebugConsole
...skipping location
__PROFILER_BASE_.$
__PROFILER_BASE_.$.fn
__PROFILER_BASE_.$.fn.init
--> hooking init
...skipping selector
...skipping jquery
...skipping length
__PROFILER_BASE_.$.fn.size
--> hooking size
__PROFILER_BASE_.$.fn.toArray
--> hooking toArray
__PROFILER_BASE_.$.fn.get
--> hooking get
__PROFILER_BASE_.$.fn.pushStack
--> hooking pushStack
__PROFILER_BASE_.$.fn.each
--> hooking each
__PROFILER_BASE_.$.fn.ready
--> hooking ready
__PROFILER_BASE_.$.fn.eq
--> hooking eq
__PROFILER_BASE_.$.fn.first
--> hooking first
__PROFILER_BASE_.$.fn.last
--> hooking last
__PROFILER_BASE_.$.fn.slice
--> hooking slice
__PROFILER_BASE_.$.fn.map
--> hooking map
__PROFILER_BASE_.$.fn.end
--> hooking end
__PROFILER_BASE_.$.fn.push
--> hooking push
__PROFILER_BASE_.$.fn.sort
--> hooking sort
__PROFILER_BASE_.$.fn.splice
--> hooking splice
__PROFILER_BASE_.$.fn.extend
--> hooking extend
__PROFILER_BASE_.$.fn.data
--> hooking data
__PROFILER_BASE_.$.fn.removeData
--> hooking removeData
__PROFILER_BASE_.$.fn.queue
当我在 jQuery.com 上(通过 Firebug)执行 $("p.neat").addClass("ohmy").show("slow");
时,我得到了一个适当的调用堆栈,但我似乎在某个地方失去了我的上下文,因为没有任何反应,我从 jQuery 得到一个 e is undefined
错误(很明显, Hook 搞砸了一些事情)。
called init
called init
called find
called find
called pushStack
called pushStack
called init
called init
called isArray
called isArray
called merge
called merge
called addClass
called addClass
called isFunction
called isFunction
called show
called show
called each
called each
called isFunction
called isFunction
called animate
called animate
called speed
called speed
called isFunction
called isFunction
called isEmptyObject
called isEmptyObject
called queue
called queue
called each
called each
called each
called each
called isFunction
called isFunction
问题是我认为我在调用时丢失了 this
上下文
return fn.apply(parent, arguments);
这是另一个有趣的怪癖。如果我在遍历之前 Hook ,即:
// hook into it (this function does nothing if obj[i] is not a function)
__PROFILER_hook(i, obj[i], obj);
// traverse the property recursively
__PROFILER_traverse(obj[i], parent+'.'+i);
.. 应用程序运行得非常好,但是由于某种原因调用堆栈被改变了(而且我似乎没有得到特定于 jQuery 的函数):
called $
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called setInterval
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called getComputedStyle
called clearInterval
.. 而不是 animation
、show
、merge
等等。现在,钩子(Hook)所做的只是说 called functionName
但最终我想执行堆栈跟踪和时间函数(通过 Java applet)。
这个问题最终变得很大,我深表歉意,但感谢您的帮助!
注意:如果您不小心,上面的代码可能会使您的浏览器崩溃。公平警告:P
最佳答案
我认为您走在正确的轨道上。当您使用 apply
时,this
的值会被破坏。 jQuery 中定义的函数可能在内部通过 apply
调用,并且取决于 this
的值。
apply
的第一个参数是将用于this
的值。您确定应该为此使用 parent
吗?
我能够通过以下方式重现该问题:
var obj = {
fn : function() {
if(this == "monkeys") {
console.log("Monkeys are funny!");
}
else {
console.log("There are no monkeys :(");
}
}
};
obj.fn.apply("monkeys");
var ref = obj.fn;
//assuming parent here is obj
obj.fn = function() {
console.log("hooking to obj.fn");
return ref.apply(obj);
};
obj.fn.apply("monkeys");
这里,函数依赖于 this
的值来打印文本 Monkeys are funny!
。如您所见,使用您的hook
算法,此上下文丢失了。 Firebug 显示:
Monkeys are funny!hooking to obj.fnThere are no monkeys :(
I made a slight change and used this
in the apply instead of obj
(the parent):
obj.fn = function() {
console.log("hooking to obj.fn");
return ref.apply(this);
};
这次 Firebug 说:
Monkeys are funny!hooking to obj.fnMonkeys are funny!
The root of your problem IMHO is that you're setting an explicit value for this
(i.e., parent
which refers to the parent object). So your hook function ends up overwriting the value of this
, which might have been explicitly set by whichever code that is calling the original function. Of course, that code doesn't know that you wrapped the original function with your own hook function. So your hook function should preserve the value of this
when it is calling the original function:
return fn.apply(this, arguments);
因此,如果您在申请中使用 this
而不是 parent
,您的问题可能会得到解决。
如果我没有正确理解您的问题,我深表歉意。不对的地方请指正。
更新
jQuery 中有两种函数。那些附加到 jQuery
对象本身(有点像静态方法)然后你有一些对 jQuery(selector)
的结果进行操作(有点像实例方法)。你需要关心的是后者。在这里,this
非常重要,因为这是您实现链接的方式。
我能够让下面的例子工作。请注意,我正在处理对象的实例,而不是对象本身。因此,在您的示例中,我将处理 jQuery("#someId")
而不仅仅是 jQuery
:
var obj = function(element) {
this.element = element;
this.fn0 = function(arg) {
console.log(arg, element);
return this;
}
this.fn1 = function(arg) {
console.log(arg, arg, element);
return this;
}
if(this instanceof obj) {
return this.obj;
}
else {
return new obj(element);
}
};
var objInst = obj("monkeys");
var ref0 = objInst.fn0;
objInst.fn0 = function(arg) {
console.log("calling f0");
return ref0.apply(this, [arg]);
};
var ref1 = objInst.fn1;
objInst.fn1 = function(arg) {
console.log("calling f1");
return ref1.apply(this, [arg]);
};
objInst.fn0("hello").fn1("bye");
我不知道这是否能解决您的问题。也许查看 jQuery 源代码会给您更多的见解 :)。我认为您的困难在于区分通过 apply
调用的函数和通过链接调用(或直接调用)的函数。
关于递归 Hook 时 Javascript 丢失上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6157882/
我创建了一个简单的钩子(Hook),我安装了它 SetWindowsHookEx(WH_CBT, addr, dll, 0); 完成后,我卸载 UnhookWindowsHookEx(0); 然后我可
我正在使用 React Hooks,当我用 mobx 的观察者包装我的组件时,我收到了这个错误。可能是什么问题?是否可以将 mobx 与 React Hooks 一起使用? import classn
我知道这个问题已经被回答过很多次了。我只是找不到解决我的问题的答案,让我相信,我要么是愚蠢的,要么是我的问题没有被解决,因为它比我更愚蠢。除此之外,这是我的问题: 我正在尝试创建一个功能组件,它从 r
我正在使用 React Navigation 的 useNavigation 钩子(Hook): 在 MyComponent.js 中: import { useNavigation } from "
我想在 gitlab 中使用预提交钩子(Hook)。我做的一切都像文档中一样:https://docs.gitlab.com/ce/administration/custom_hooks.html 在
我最近在和一些人谈论我正在编写的程序时听到了“hook”这个词。尽管我从对话中推断出钩子(Hook)是一种函数,但我不确定这个术语到底意味着什么。我搜索了定义,但找不到好的答案。有人可以让我了解这个术
我正在寻找一个在页面创建或页面更改后调用的钩子(Hook),例如“在导航中隐藏页面”、“停用页面”或“移动/删除页面“ 有人知道吗? 谢谢! 最佳答案 这些 Hook 位于 t3lib/class.t
我正在使用钩子(Hook)将新方法添加到 CalEventLocalServiceImpl 中... 我的代码是.. public class MyCalendarLocalServiceImpl e
编译器将所有 SCSS 文件编译为 STANDALONE(无 Rails)项目中的 CSS 后,我需要一个 Compass Hook 。 除了编辑“compiler.rb”(这不是好的解决方案,因为
我“.get”一个请求并像这样处理响应: resp = requests.get('url') resp = resp.text .. # do stuff with resp 阅读包的文档后,我看到
我们想在外部数据库中存储一些关于提交的元信息。在克隆或 checkout 期间,应引用此数据库,我们将元信息复制到克隆的存储库中的文件中。需要数据库而不是仅仅使用文件是为了索引和搜索等...... 我
我有一个 react 钩子(Hook)useDbReadTable,用于从接受tablename和query初始数据的数据库读取数据。它返回一个对象,除了数据库中的数据之外,还包含 isLoading
在下面的代码中,当我调用 _toggleSearch 时,我同时更新 2 个钩子(Hook)。 toggleSearchIsVisible 是一个简单的 bool 值,但是,setActiveFilt
问题 我想在可由用户添加的表单中实现输入字段的键/值对。 参见 animated gif on dynamic fields . 此外,我想在用户提交表单并再次显示页面时显示保存的数据。 参见 ani
当状态处于 Hook 状态时,它可能会变得陈旧并泄漏内存: function App() { const [greeting, setGreeting] = useState("hello");
const shouldHide = useHideOnScroll(); return shouldHide ? null : something useHideOnScroll 行为应该返回更新后
我正在使用 React-native,在其中,我有一个名为 useUser 的自定义 Hook,它使用 Auth.getUserInfro 方法从 AWS Amplify 获取用户信息,并且然后获取返
我正在添加一个 gitolite 更新 Hook 作为 VREF,并且想知道是否有办法将它应用于除 gitolite-admin 之外的所有存储库。 有一个更简单的方法而不是列出我想要应用 Hook
如何使用带有 react-apollo-hooks 的 2 个 graphql 查询,其中第二个查询取决于从第一个查询中检索到的参数? 我尝试使用如下所示的 2 个查询: const [o, setO
我是 hooks 的新手,到目前为止印象还不错,但是,如果我尝试在函数内部使用 hooks,它似乎会提示(无效的 hook 调用。Hooks can only be called inside o
我是一名优秀的程序员,十分优秀!