Javascript,有面向对象特性的函数式语言。之前虽然一直在用AngularJS来做一些前端工作,但是一直将它当做C来用,再后来接触到Nodejs,慢慢的感受到这门语言的强大,只是限于对它的理解,写出来的代码很烂。
与经典面向对象语言不同,Javascript的面向对象是通过prototype来展现的,这种方式比较难以理解,至少对我是这样。所谓经典面向对象语言指的是C++/Java这一类语言,有类和对象,对象即为类的实例。Javascript,函数是第一等公民,对象也是通过函数来表现的,同样是用function关键字来声明。
上周末,我整理了一下所有对Javascript的疑惑,用一些代码来打印我所思考的内容,总共有4个例子。
// test 1 var test = function () { var value = 1; var getValue = function () { return value; }; }; var test1_1 = new test(); console.log('-----------------test1----------------'); console.log(test1_1); test.prototype.getValue1 = function () { return 1.1; }; console.log(test.prototype); console.log(test1_1.__proto__); console.log('--------------------------------------\n');
// 用node运行后打印的命令行结果如下:
-----------------test1---------------- {} { getValue1: [Function] } { getValue1: [Function] } --------------------------------------
关于new,stackoverflow上有一个帖子http://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript。
第二段代码:
// test 2 var test2 = function () { var value = 2; return { getValue : function () { return value; } }; }; var test2_1 = test2(); console.log('-----------------test2----------------'); test2.prototype.setValue1 = function (value) { this.value = value; }; test2.prototype.getValue1 = function () { return this.value; }; console.log(test2.prototype); console.log(test2_1.getValue()); console.log(test2_1.__proto__); var test2_2 = new test2(); console.log(test2_2.getValue()); console.log(test2_2.__proto__); console.log('--------------------------------------\n');
// 结果:
-----------------test2---------------- { setValue1: [Function], getValue1: [Function] } 2 {} 2 {} --------------------------------------
test2_1以及test2_2实际上是test2函数运行后的返回,无论是否是new,都是一个Object,这个就是一个闭包的用法,用来访问这个这个对象的内部变量,这个闭包的原型就是Object,也即是{}。而源对象由于明确的给它的prototype加了两个函数。
第三段代码及结果:
// test 3 var test3 = function() { var that = this; that.value = 3; that.getValue = function () { return that.value; }; }; console.log('-----------------test3----------------'); test3.prototype.setValue1 = function (value) { this.value = value; }; test3.prototype.getValue1 = function () { return this.value; }; console.log(test3.prototype); var test3_1 = new test3(); console.log(test3_1.getValue()); console.log(test3_1.getValue1()); console.log('--------------------------------------\n'); // 结果: -----------------test3---------------- { setValue1: [Function], getValue1: [Function] } 3 3 --------------------------------------
第四个例子:
// test 4 var test4 = function () { var that = this; that.value = 4; }; test4.prototype = new test3(); test4.prototype.getOwnValue = function () { return this.value; }; console.log('-----------------test4----------------'); console.log(test4.prototype); var test4_1 = new test4(); console.log(test4_1.getValue()); console.log(test4_1.getOwnValue()); console.log(test4_1.__proto__); console.log(test4_1.__proto__.__proto__); console.log('--------------------------------------\n'); // 结果: -----------------test4---------------- { value: 3, getValue: [Function], getOwnValue: [Function] } 3 4 { value: 3, getValue: [Function], getOwnValue: [Function] } { setValue1: [Function], getValue1: [Function] } --------------------------------------
第三和第四个例子结合起来看,test3在未给原型增加变量之前依然是{},增加之后就变成了{ setValue1: [Function], getValue1: [Function] },test4继承自test3,意思就是test4的原型指向test3的一个实例,这里test4里面的value并没有覆盖掉test3中得value,各自拥有各自的作用域,这个很好理解。最后打印了test4_1的原型链。
请忽略谭浩强命名风格的代码:-)
关于this的用法,请参考http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html,这里有大牛们写得东西就不卖弄了。