Javascript 面向对象化写法——语法篇
本编参考:http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html 系列,总结如下
一.几个重要关键字
1.this —— 指当前的对象,若在全局范围,则指当前页面对象window,如果是函数中使用this,则指的是调用这个函数的对象。firebug一下demo:
function sayHi() {
console.debug(this);
}
var obj = {
sayHi: sayHi,
sayHi2: function() {
return function() {
console.debug(this);
}
}
};
sayHi(); // 结果为window对象
obj.sayHi(); // 结果为obj对象
obj.sayHi2()(); // 结果为window对象解析:在javascript当中,一切皆为对象,function也是,所以可以看到全局函数sayHi可以像变量一般pass给obj的sayHi属性。三个函数调用的,前两个不用多解析,看第三个,其实等价于下面写法:
var f = obj.sayHi2(); f();
sayHi2函数返回一个函数对象,赋予变量f,f就是个函数了,然后 f 被window调用执行,如此就这么回事了。
再看一个demo:
function TestThis () {
this.oham = 'oham';
console.debug(this);
}
TestThis(); // window对象
new TestThis(); // TestThis 对象实例本身对于TestThis();的结果不奇特,而new TestThis();之神奇在于new,其内部机制在下就不懂了...只可以看出,通过new XXX();这样调用,XXX方法中的this就指向XXX构造出的对象实例本身了。
2.apply与call
接着上面的例子,介绍apply 与 call,它们均是全局函数,归Function所有(Function属于javascript内部对象,不是Function的对象是没有这两个方法的)。 接上文的demo:
... obj.sayHi2()(); //结果为window对象 obj.sayHi2().apply(obj); // 结果为obj对象 obj.sayHi2().call(obj); // 结果为obj对象
apply 与 call 的 作用是改变函数中this的指向,即使函数看起来好像被谁调用一样,其作用域也是那个谁的。
apply 与 call 的区别,仅仅是参数定义不同,请看如下demo:
function ml(me, mm) {
console.log(this);
if( this === window ) {
console.log(me + ',' + mm + ' not possible in public');
}else {
console.log(me + ',' + mm + ' so happy');
}
}
var hotel = {};
ml('me', 'mm');
ml.apply(hotel, ['me', 'mm']);
ml.call(hotel, 'me', 'mm');请实践一下,代码,便知知道,apply的定义的参数列表是个数组,call是参数列(估计是function call(obj, params...))。
**至此深觉有必要介绍javascript中闭包的概念。闭包,指的是语法上表示包含不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。
demo(以下摘自w3cschool):
var sMessage = "hello world";
function sayHelloWorld() {
alert(sMessage);
}
sayHelloWorld();在上面这段代码中,脚本被载入内存后,并没有为函数 sayHelloWorld() 计算变量 sMessage 的值。该函数捕获 sMessage 的值只是为了以后的使用,也就是说,解释程序知道在调用该函数时要检查 sMessage 的值。sMessage 将在函数调用 sayHelloWorld() 时(最后一行)被赋值,显示消息 "hello world"。
再看看自己的一个demo:
var outSide = 'madom';
var room = {
mm : 'mm',
watch: function(me) {
return function () {
if(this.outSide) { //尝试
console.debug(me + ' can watch ' + this.outSide);
}else {
console.debug(me + ' can\'t watch outSide, but never mind.');
}
if(this.mm) { //尝试
console.debug(me + ' can watch ' + this.mm);
}else {
console.debug(me + ' can\'t watch mm, not happy');
}
}
},
touch: function (me) {
if(this.outSide) { //尝试
console.debug(me + ' can touch ' + this.outSide + ', but won\'t do that');
}else {
console.debug(me + ' can\'t touch outSide, but never mind.');
}
if(this.mm) { //尝试
console.debug(me + ' can touch ' + this.mm + ', so cool...');
}else {
console.debug(me + ' can\'t touch mm, not happy');
}
}
};
var watchFunc = room.watch('I');
//全局调用
watchFunc();
console.log('-------------------------------------');
//room范围调用
watchFunc.apply(room);
console.log('============================================');
//room范围调用
room.touch('I');
console.log('----------------------------------------');
//全局调用
room.touch.apply(this, ['I']);结果为:
"I can watch madom" "I can't watch mm, not happy" "-------------------------------------" "I can't watch outSide, but never mind." "I can watch mm" "============================================" "I can't touch outSide, but never mind." "I can touch mm, so cool..." "----------------------------------------" "I can touch madom, but won't do that" "I can't touch mm, not happy"
这个结果好解析,this为谁调用就是谁,接着请尝试把demo中标有//尝试的if 语句中的"this."删除,
情况会如下:
"I can watch madom" "Uncaught ReferenceError: mm is not defined (line 15)"
执行到watch函数的if(mm) 这句出错了,无论apply部apply结果都一样,原因具体我就不清楚了,这里只是证实了,对于一个变量如name, name 并不是等价于this.name(跟java大不同) ,JS的解释程序不会为你做这个,当函数被调用的时候,它只会先从当前函数范围去找,若无命中变量,则直接到全局范围去找。可以把mm部分的代码去掉,只留outSide的,结果是无论apply与否,结果都能访问的变量outSide。
3.prototype——对该对象的对象原型的引用。对于所有的对象,它默认返回 Object 对象的一个实例(w3c定义)。
prototype本质上还是一个JavaScript对象,个人觉得上述定义不太妥当,实际上prototype感觉更像对象的一个模板,而非实例, 并且每个函数都有一个默认的prototype属性。 以demo为证:
var room = {
mm: 'mm',
watch: function () {
}
};
console.log(room.prototype); // undefined
console.log(room.valueOf()); // room object