我最近在重写JavaScript中的JavaScript函数的必要性,动态。 的难易程度,我做到了,这多么好玩,我感到震惊。
在这里我有一些HTML:
<div id="excelExport1234"
onclick="if(somestuff) location.href='http://server/excelExport.aspx?id=56789&something=else'; else alert('not important');"
>Click here to export to excel</div>
我不能改变输出HTML,但我需要一个额外的参数添加到该链接。 我开始思考这个问题,并意识到我可能只是这样做:
excelExport = $('excelExport1234');
if (needParam)
eval('excelExport.onclick = ' + excelExport.onclick.toString().replace("excelReport.aspx?id", "excelReport.aspx?extraParam=true&id") + ';');
else
eval('excelExport.onclick = ' + excelExport.onclick.toString().replace("extraParam=true&", "") + ';');
和它的工作就像一个冠军! excelExport.onclick返回一个函数对象,我转换为字符串,并做一些字符串MANIP。 因为它现在的形式“功能(){...}”,我刚回去,并将其分配给DOM对象的onclick事件。 这是一个有点难看不必使用eval,但据我所知没有一个javascript函数的构造,可以采取一串代码,并把它变成一个对象很好。
不管怎样,我的观点是不是说我是超级聪明(我不是),我的观点是, 这是很酷的 。 我知道的JavaScript是不是能够做到这一点的唯一语言。 我听说口齿不清已宏年这一确切目的。 除了真正神交宏,你需要真正神交口齿不清,我不神交,我只是“种得到它”。
所以我的问题是: 在什么其他语言你能(轻松)动态重写功能,你能告诉我一个简单的例子? 我想看看还有什么地方你能做到这一点,它是如何做!
(另外,我不知道这个标签作为,所以我把随机猜测)
Answer 1:
LISP在这最终的语言。 LISP功能实际LISP名单,这意味着你可以操纵LISP源代码,就好像它是任何其他数据结构。
下面是它如何工作的一个很琐碎例如:
(define hi
(lambda () (display "Hello World\n")))
;; Displays Hello World
(hi)
(set! hi
(lambda () (display "Hola World\n")))
;; Displays Hola World
(hi)
然而,这可能在函数是第一类对象的任何语言。 一个本语法LISP的权力的最有趣的陈列柜在其宏系统。 我真的不觉得我可以做专题公正,所以如果你有兴趣阅读这些链接:
http://en.wikipedia.org/wiki/Macro_(computer_science)#Lisp_macros
http://cl-cookbook.sourceforge.net/macros.html
Answer 2:
我想这取决于究竟你定义为“轻松动态重写”。 例如,在.net中,您有Func键型和lambda表达式,它允许您定义功能变量或临时匿名函数如。
int[] numbers = {1, 2, 3, 4, 5};
Func<int[], int> somefunc;
if (someCondition)
{
somefunc = (is => is.Sum());
} else {
somefunc = (is => is.Count());
}
Console.WriteLine(somefunc(numbers).ToString());
以上是任一计数项目中一个整数数组,或使用动态创建的功能受到一些任意条件求和然后非常人为的例子。
注-请不要指出的是,这些东西可以在不lambda表达式很容易地完成(其中他们显然可以)我只是想写一个很简单的例子来演示在C#概念
Answer 3:
自修改代码也被称为退化的代码。 这通常被认为是一件坏事,它曾经是高级语言的一个目标,以防止它被随便写。
这是从维基百科条目:
自修改代码是被一些人视为一种不好的做法,这使得代码难于阅读和维护看到。 然而有方式,其中自修改仍然被认为是可接受的,例如子程序指针时被动态地改变的 - 即使效果几乎是相同的直接修改。
Answer 4:
我认为这是大多数动态语言的情况。 这里是在Python一个例子
def f(x):
print x
def new_function(x): print "hello", x
f("world")
f = new_function
f("world")
输出是
world
hello world
我认为,这样的技术应谨慎使用
Answer 5:
计划可以让你做到这一点。
(define (salute-english name) (display "Hello ") (display name))
(define (salute-french nom) (display "Salut ") (display nom))
现在,您可以通过分配重新定义fonction salute
变量为正确的函数,要么salute-english
或salute-french
,像这样:
(define salute salute-english)
(define (redefined-the-salute-function language)
(if (eq? language 'french)
(set! salute salute-french)
(set! salute salute-english)))
更多generaly函数式编程语言允许你这样做或功能是一流的价值。 功能可以被操纵,传来传去,有时赋值给变量等。 然后,名单包括:Lisp语言 , 计划 , 迪伦 ,OCaml中和SML。 具有一流的功能有些语言包括Python和Ruby,Smalltalk和我想的Perl。
需要注意的是,当你有一个互动的语言,你可以交互地输入程序,功能的重新定义/方法必须是可能的:REPL必须能够做到这一点,以防万一你发生重新输入的已定义函数的定义。
Answer 6:
我以前在TCL做这一切的时候,它是一个微风和表现的很出色。 我可以调查通过网络出头接口,然后动态创建一个定制的接口来访问和控制的事情。 例如,你可以把从一个普通的SNMP库自定义的SNMP接口。
我没有用它,但是C#有一些内置生成它自己的字节码,这是相当可观的支持。
我已经做了这样的事情在C作为很好,但它是不可移植的,几乎从来不值得冒这个险。 它有时是用于“自优化”的代码,以生成相应的C函数以最佳方式处理给定的数据集的技术。
Answer 7:
你能做到这一点在C ++中,但它不会是容易的,安全的,或推荐。
- 生成的源代码的文本
- 调用编译器(叉&EXEC)来构建动态库。 在海湾合作委员会,你可以把你想要编译标准输入的源代码,它并不一定要在一个文件中。
- 负载(在Linux上的窗口调用LoadLibrary(),dlopen的())库
- 得到一个函数指针,以任何你想要的功能(在Linux GetProcAddress的()在Windows上,则dlsym())
- 如果要替换现有的功能,如果它是一个虚函数,你可以修改v表指向新的功能(该部分特别是一个可怕的想法充满了危险)。 V型表或它的格式的位置是不是C ++标准的一部分,但我使用的所有工具链并没有超出自己保持一致,所以一旦你弄清楚他们如何做到这一点,它可能不会打破。
Answer 8:
很容易,在Perl。
*some_func = sub($) {
my $arg = shift;
print $arg, "\n";
};
some_func('foo');
重新萨姆藏红花的要求:
*hello_world = sub() {
print "oops";
};
hello_world();
*hello_world = sub() {
print "hello world";
};
hello_world();
Answer 9:
在PLSQL:
create or replace procedure test
as
begin
execute immediate '
create or replace procedure test2
as
begin
null;
end;
';
end;
/
Answer 10:
下面是其他的东西在Python(除了LUC的答案),这我不建议,但只是为了显示它 - 有EXEC,可以执行,你可以建立成为任何代码串...
I / O此处显示为一个Python 2.5.2解释器会话。 只是构建字符串的一些简单的例子,从子执行(>>>是提示符的解释)...
>>> def_string = 'def my_func'
>>> param_string_1 = '():'
>>> param_string_2 = '(x):'
>>> do_string_1 = ' print "Do whatever."'
>>> do_string_2 = ' print "Do something with", x'
>>> do_string_3 = ' print "Do whatever else."'
>>> do_string_4 = ' print "Do something else with", x'
>>> def_1 = '\n'.join([def_string+param_string_1, do_string_1, do_string_3])
>>> print def_1
def my_func():
print "Do whatever."
print "Do whatever else."
>>> exec def_1
>>> my_func()
Do whatever.
Do whatever else.
>>> def_2 = '\n'.join([def_string+param_string_2, do_string_2, do_string_4])
>>> print def_2
def my_func(x):
print "Do something with", x
print "Do something else with", x
>>> exec def_2
>>> my_func('Tom Ritter')
Do something with Tom Ritter
Do something else with Tom Ritter
>>>
Answer 11:
平凡的红宝石:
def hello_world; puts "oops"; end
hello_world
# oops
def hello_world; puts "hello world"; end
hello_world
# hello world
当然,这个例子很无聊:
require "benchmark"
# why oh _why
class Object
def metaclass; class << self; self; end; end
def meta_eval &blk; metaclass.instance_eval &blk; end
end
class Turtle
end
def make_it_move(klass)
klass.send(:define_method, :move) { |distance|
puts "moving #{distance} meters"
sleep(0.1 * distance)
}
end
make_it_move(Turtle)
turtle = Turtle.new
turtle.move(1)
# moving 1 meters
def profile(instance, method)
instance.meta_eval do
m = instance_method(method)
define_method method do |*a|
puts "Benchmarking #{instance.class} #{method}"
puts Benchmark.measure {
m.bind(instance).call(*a)
}
end
end
end
profile(turtle, :move)
turtle.move(10)
# Benchmarking Turtle move
# moving 10 meters
# 0.000000 0.000000 0.000000 ( 1.000994)
Turtle.new.move(3)
# moving 3 meters
上面的代码:
- 定义一个类空白
- 添加一个方法,它
- 抓住一个实例
- 截获在该实例方法只
Answer 12:
改变什么功能确实在很多语言的支持,并且它并不像你想象的那么复杂。 在功能性的语言,函数是值和函数名是被绑定到这些像任何变量的符号。 如果语言允许您将符号重新分配给不同的功能,这是微不足道的。
我觉得更有趣的功能是得到一个功能的源代码(能力toString
以上),并从字符串(创建一个新的功能eval
在这种情况下)。
文章来源: In what languages can you dynamically rewrite functions on the fly?