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');
?
?
