简体   繁体   English

定义函数与 function.prototype 的属性

[英]Defining properties on function vs on function.prototype

tl;dr In case you are familiar with how javascript works, skip to the "question" part. tl;dr如果您熟悉 javascript 的工作原理,请跳到“问题”部分。

I come from javascript, where we use the prototype chaining to define our "class" methods such as:我来自 javascript,我们使用原型链来定义我们的“类”方法,例如:

function MyClass(){
    return this
}
MyClass.prototype.method = function(){
    // do stuff
}
MyClass.directPropFunction = function(){
    // do direct stuff
}

MyClass.method()                    // doesn't work
MyClass.directPropFunction()        // works
new MyClass()                       // instantiates an object from said "class"
new MyClass().method()              // now it works!
new MyClass().directPropFunction()  // however now no longer works.

In other words, defining direct properties on function could be considered static methods, where as defining properties on the prototype can be considered regular methods.换句话说,在函数上定义直接属性可以被认为是static方法,而在prototype上定义属性可以被认为是常规方法。 All this rides on the fact that we "fake" classes by using functions as constructors for objects which we then access and use their prototype chains to do magic stuff.所有这一切都基于这样一个事实,即我们通过使用函数作为对象的构造函数来“伪造”类,然后我们访问并使用它们的原型链来做魔术。

One important thing to note is that even the .method that is declared on the prototype is not created for each instance of the object.需要注意的一件重要事情是,即使是在原型上声明的.method也不是为对象的每个实例创建的。 Does LUA have a "proper" way to extend function objects? LUA 是否有“正确”的方式来扩展函数对象?

Question:题:

I have been fiddling around with LUA a bit and have come across this: I got to ask, since I do not know how it works internally, what is the difference and what is the preferred way of doing things?我一直在摆弄LUA并遇到了这个问题:我不得不问,因为我不知道它在内部是如何工作的,有什么区别以及首选的做事方式是什么? Also, I am not sure if LUA has the whole "faking" classes, but I wouldn't use it anyway probably, so which of the methods shown bellow is the "correct" way to do things?另外,我不确定 LUA 是否具有整个“伪造”类,但我可能无论如何都不会使用它,那么下面显示的哪种方法是“正确”的做事方式?

function Foo()
    -- do stuff
end
Foo.method = function()
    -- do stuff
end
Foo.prototype.protoMethod = function()
    -- do stuff
end

What I want to achieve is have the following:我想要实现的是以下几点:

function doSomething()
    -- does something, duh
    -- return uniqueID
end
doSomething.revert = function(uniqueID)
    -- reverts stuff
end

and then I would be able to do both:然后我就可以做到这两点:

local a = doSomething()
doSomething.revert(a)

so what is the right approach?那么正确的方法是什么?

Consider this exercise:考虑这个练习:

local function reversible (func)
    local states = {}
    states [func] = states [func] or {}
    return function (...)
        local result = func (...)
        states [func] [result] = {...}
        return result
    end, function (result)
        return unpack (states [func] [result])
    end
end

local square, root = reversible (function (a)
    return a ^ 2
end)

local initial = -2
local squared = square (initial)
local reversed = root (squared)

io.write ('initial = ' .. tostring (initial) .. ', squared = ' .. tostring (squared) .. ', reversed = ' .. tostring (reversed) .. '\n')

Of course, in this example, the "state" that is restored consists of only function arguments;当然,在本例中,恢复的“状态”仅由函数参数组成; so that func has to be pure.所以func必须是纯的。 It is assumed that the original function returns only obe value (if more, states should be indexed with hashes of func results packed into a table).假设原始函数仅返回 obe 值(如果更多,则应使用打包到表中的func结果的散列索引states )。

Unlike JavaScript, in Lua functions do not have properties, and objects have no prototypes.与 JavaScript 不同的是,Lua 中的函数没有属性,对象也没有原型。 However, Lua tables have metatables .但是,Lua 表有元表

Also, function properties can be emulated by table fields, if the table's metatable has a field __call , which is used when a table is called like a function.此外,如果表的元表具有字段__call ,则可以通过表字段模拟函数属性,当表像函数一样被调用时使用。 The example below imprements the pseudo-property revert and also allows multiple returns for the original finction:下面的示例实现了伪属性revert并且还允许对原始功能进行多次返回:

local function hash (array)
    return table.concat (array, ',')
end

local function reversible (func)
    local states = {}
    states [func] = states [func] or {}
    local wrapped = {
        revert = function (...)
            return unpack (states [func] [hash {...}])
        end
    }
    setmetatable (wrapped, {
        __call = function (tbl, ...)
            local results = {func (...)}
            states [func] [hash (results)] = {...}
            return unpack (results)
        end
    })
    return wrapped
end

local square = reversible (function (a)
    return a ^ 2
end)

print ('square (-2)', square (-2))
print ('square.revert (4)', square.revert (4))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM