??JavaScript毕竟不是Java,它也不是纯粹的面向对象语言,我的这篇博文只是模拟相关面向对象编程。同时也是深入学习JavaScript,将它与Java思想结合遇到的一些问题,在这里进行总结。
JavaScript模拟面向对象
函数是类
function Obj() {
};
var o1 = new Obj();
console.log("o1:",o1);
console.log("o1 instanceof Obj",o1 instanceof Obj);
var o2 = new Obj;
console.log("o1 == o2",o1 == o2);
console.log("o2 instanceof Obj", o2 instanceof Obj);
上述想说明function是一个类,因为它可以用new产生自己的对象。
o1、o2是Obj的一个实例化对象,而Obj已经可以抽象成类的概念了。
函数中各种变量的声明
var Fun = function () {
varOne = 100;
var varTwo = 200;
this.varThree = 300;
console.log(window);
}
var fun1 = new Fun();
fun1.varThree = "abc";
console.log("fun1", fun1);
var fun2 = new Fun;
console.log("fun2", fun2);
这里有window的输出,说明Fun函数被调用了。也同时可以类比无参构造。也就说明,function是函数,是类,也是类的构造方法。
window里多出 Fun,varOne,fun1和fun2,给window加的键值对(成员)。在JS里,只要被称为对象的,都可以看作是一个Map,里面可以有键值对。这样看来window也是一个对象。
1.函数内无任何前缀变量
??在一个函数里面直接写一个没有任何前缀的变量,其前缀默认是window,相当于varOne <=> window.varOne,给window对象加键值对(成员)。window也是个对象,它再大也是个对象,里面由很多键值对组成的。所以以前称它为全部变量是错误的,它只是window对象底下的一个键值对而已。
2.函数内定义var变量
??函数内定义的var varTwo = 200; 是函数的局部变量,将随着函数运行结束而释放,用的是堆栈空间。局部变量用的是系统堆栈,随着函数运行结束,栈顶指针下移,局部变量用的堆栈空间被释放了。对所有语言来说,局部变量都是如此。
3.函数内加this修饰的变量
??例如this.varThree = 300。varThree成了对象fun1和fun2的(成员)键值对。更改fun1对象的varThree的值,而fun2的不会改还是函数执行(构造方法)出来的。且,这类成员是public的,或者说,模拟public成员。就像Java里面类的成员一样,每一个该类的对象都拥有自己的成员!只不过和Java不一样的地方,Java需要前面给确定的类型,但JavaScript是弱类型,没有这么一说。同时Java成员还可以有修饰符。
关于函数内的this
??参照Java中的this,在Java中new的时候会调用构造方法,构造方法被对象调用,这个this其实就是那个调用构造方法的对象。照搬到JavaScript中也可以解释通。JavaScript中调用函数后,函数里的this自动被替换为调用该函数的对象。
前期小结:在JavaScript中
- 函数是函数:可以调用的,直接写在script标签下是window对象的一个键值对。
- 函数也是类:参考Java的思想,可以实例化对象出来。
- 函数也是类的构造函数:在new对象时被自动执行
- 函数还是对象:可以有自己的键值对
在JavaScript可以类比Java记住:对象(map)是由一些键值对(成员)组成的。
练习:面向对象思想编写Complex类
??又感觉回到学习Java的第一节课编写Complex类。速速写出。
var Complex = function () {
this.real = 0.0;
this.vir = 0.0;
this.setReal = function (real) {
this.real = real;
}
this.setVir = function (vir) {
this.vir = vir;
}
this.getReal = function () {
return this.real;
}
this.getVir = function () {
return this.vir;
}
this.toString = function () {
return "(" + this.real + ", " + this.vir +")"
}
}
var complexOne = new Complex();
complexOne.setReal(1.2);
complexOne.setVir(9.8);
console.log("complexOne:", "" + complexOne);
需要注意的点时如果要获得成员的值,一定要记得加this修饰,否则可能会获取widow下同名的值,没达到预期目标。
模拟静态成员初尝试
??我们知道Java中需要一种属于整个类而不独属于某个实例对象的成员称为静态变量。JavaScript可以实现吗?因为没有修饰符static 这种关键字,那么通过类.名称 可以吗?尝试下。
var Complex = function () {
}
Complex.staticField = 5;
var complexOne = new Complex();
console.log(complexOne.staticField);
??结果为undefined 。说明未定义,没有办法访问到。这不是静态成员。仔细分析结合上文我们得知原因:我们知道Complex是个类,但它也是个对象,上述操作只相当于给Complex这个对象增加个键值对,而不是给它实例化对象增加的。
??那么JavaScript中的静态成员应该如何定义呢?这个问题我们先放一放,因为它要牵扯到一个重要的JavaScript中的原型(Prototype)的问题!
初探究prototype原型
??在JavaScript中,所有的”类“(函数)都存在”原型“,型是类型的意思;原是说明的意思,有点meta的意思。
??这个meta往Java方向想,例如String.class 和Complex.class ,这个class是所有类都有的一个单例的、静态的元数据。元数据是解释数据的数据,我们的反射机制就是基于这个class而来的,class描述这个类有哪些成员,哪些方法什么的。
??我们经常锁的就是这个class。因为多个同一个类实例化的对象需要找到一个他们都认识的锁。类.class是对象都认识的,所以用它来保证多线程安全问题。
synchronized (Complex.class) {
}
??JavaScript的类都有一个prototype(原型);JavaScript的对象都绝对不会存在prototype!这就是区分类和对象的方法!即,如果想区分一个对象是否也是类,则,查看其是否存在prototype成员!若存在,则它既是对象,也是类;若不存在(undefined),则它仅仅是对象!
未完待续…
|