非常简单地讲一下lua的下面几个概念:


1.metatable
可以用来运算符重载。
每个lua表都可以设metatable,默认为nil。对表的元表metatable,添加__add、__sub 、__multi、__div就可以实现系统的加减乘除(+ - × ÷)啦。当setmetatable(tableOne, tableOther),就把tableOne的metatable设成了tableOther。


2.__index
类似__add, __sub等,是定义在metatable上的方法。正如其名index, 即索引,其作用就是:如果在当前表里找不到某个方法或属性,那么就会去调用__index方法并返回其执行结果。__index这种特性经常用来模拟面向对象的 类。


3.__newindex
如果对某个lua表不存在的某个方法或属性赋值,那么就会先去找元表的__newindex函数。若存在,则执行该函数;不存在,就是一般的表的赋值。
__index和__newindex联合起来,就相当于重载了一个完整的"[]"运算符。__index相当于取值,__newindex相当于赋值。


4.__rawget和__rawset
有些时候,我们不想让lua在元表里找,只想找自己的;那么就用__rawget和__rawset,看名字就知道:rawget,即原始获取;rawset,即原始赋值。


5.示例
下面用cocos的例子来解释下上面的概念。cocos定义了个cc.exports用来管理全局变量。其源代码如下:

local __g = _G
cc.exports = {}
setmetatable(cc.exports, {
     __newindex = function(_,name,value)
          rawset(__g,name,value)
     end,
     
     __index  = function(_, name)
          return rawget(__g,name)
     end
})



_G是lua自带的全局变量表,我们定义的所有全局变量都在这个_G表里。这段代码意思是对cc.exports这个表,取值或赋值都是相当于在_G里取值赋值。 


于是我有一个疑问,既然对cc.exports表的操作,相当于在_G里操作;那这个cc.exports还有什么意义?

我现在只能猜想有两个好处:

1.方便团队协作的规范,所有的全局变量必须以cc.exports.YOURVAR的形式来写。所有的局部变量必须以local形式定义。那么我在全局搜cc.exports就能很快搜到定义了哪些全局变量。

2.方便以后扩展。万一全局变量管理以后某个牛人想出了什么高端的技巧,就可以在cc.exports里快乐的修改了。



如果第一个好处是真的,那么肯定也会有机制来防止程序员意外定义全局变量。为什么会意外定义呢?这是因为lua定义全局变量非常简单,只要随便在哪里写下 a = {}, 那么就放在了_G表里。这个一不小心很容易定义了,如果这种失误越来越多,那么_G会越来越大,所占内存也会越来越大。

果然,cocos也定义了个方法来防止程序员不小心污染_G表: 


function cc.diable_global()
    setmetatable(_g,{
        __newindex = function(_,name,value)
        	error(string.format("USE \" cc.exports.%s = value \" INSTEAD OF SET GLOBAL VARIABLE",name),0)
        end
    })
end

if CC_DISABLE_GLOBAL then
    cc.disable_global()
end




只要将CC_DISABLE_GLOBAL设为true,那么你就不能定义全局变量了。