1.2 模拟面向对象
要说到面向对象,Java的语法规范应该会比较熟悉,C#也同样。
谈到面向对象就得做到封装,对于Javascript如何做封装才最有效呢?不禁让我联想到闭包
1.2.1 闭包
? 闭包是能够读取其他函数内部变量的函数。
1.2.2 链式作用域
? JavaScript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。
所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
?
综合以上两点,Js++ 的面向对象都在函数体内实现“成员变量”和“成员函数”。
1.2.3 现在疑问就是这些“成员变量”和“成员函数”如何能开放出来,使得外界可以访问呢?其实有普遍有两种方法:
A. 将“成员变量”和“成员函数”做json成员,然后通过 return 关键字 从函数返回。
var D = function(){ return { //然后通过 return 关键字 从函数返回。 v:1, fun:function(){ } }; }; var Class = D();
?
?
B. 通过传出一个对象,将“成员变量”和“成员函数”扩展到此对象中
?
var D = function($){ $.extend($,{ // “成员变量”和“成员函数”扩展到此对象$ a:1, fun:function(){ } }); }; var Class = {}; D(Class);
?
?
C. 其实有一种更加巧妙的方法是通过 Function.caller
Function.caller
? 返回一个对函数的引用,该函数调用了当前函数。
? 有了此caller,我们就可以“成员变量”和“成员函数”存入到外围的函数上
?
function jpublic(overrides) { $.extend(jpublic.caller.$Public, overrides); } function jprotected(overrides) { $.extend(jprotected.caller.$Public, overrides); } var D = function(){ // 外围的函数 jpublic({ // “成员变量”和“成员函数” 会存入外围的函数的$Public变量上 a:1, fun:function(){ } }); jprotected({ b:2 }); }; var Class = D().$Public;
?
此时,就可以定义类似public,protected,private等关键字来区分类“成员变量”和“成员函数”不同作用域
?
?
1.2.4 关于继承的模拟
? 可以采用原型链的方式
?
1.2.5 对父类成员的“成员函数”的访问
? ? 由于在继承的模拟原型链中,已将子类和父类prototype通过superclass关联,因此可以这样访问:
'class A'.j(function(){ jpublic({ fun:function(){ } }); }); 'class B extends A'.j(function(){ jpublic({ fun:function(){ B.superclass.fun.apply(this,arguments); //通过superclass关联访问父类成员的“成员函数” fun // 可用 jsuper(this); 替换 B.superclass.fun.apply(this,arguments); } }); });
?
B.superclass.fun.apply(this,arguments); 这个写太长,而且麻烦,有没有更好的呢,经过多次的实践,终于又回到了Function.caller
?
function jsuper(jthis) { var m = jsuper.caller; // 获得当前调用者,以上的例子为"fun" 函数 if (m.methodname && m.owner) { // 在类定义时,已将每个“成员函数”的函数名和所属的类的构造函数存入到每个“成员函数”中 var method = m.methodname; var owner = m.owner; var args; if (arguments.length > 1) { // 如果 jsuper 有传入参数,则采用传入参数,否则采用 fun 的 arguments args = $.toArray(arguments, 1); } else { args = $.toArray(m.arguments); } return owner.superclass[method || 'constructor'].apply(jthis, args); //访问父类成员的“成员函数” fun } return null; }
?
1.2.6 在“成员函数”中使用“静态变量”
? Js++ 将静态变量存在类的构造函数中,可通过 jstatic.caller.owner获取构造函数
function jstatic(overrides) { if (arguments.length == 0) { return jstatic.caller && jstatic.caller.owner; //在类定义时,已将每个“成员函数”的函数名和所属的类的构造函数存入到每个“成员函数”中 } return $.extend(jstatic.caller.$Static, overrides); }
?
?
?
1.2.7 完整例子:
?
'class C extends P implements I'.j(function(csuper){ jstatic({ a:1 }); jpublic({ constructor: function () { jsuper(this); }, echo:function(){ console.log(jstatic().a); } }); jprotected({ }); jprivate({ }); },'alias class name');
?
?