JavaScript

JavaScript中this关键字使用方法详解

在面向对象编程语言中,对于this关键字我们是非常熟悉的。比如C++、C#和Java等都提供了这个关键字,虽然在开始学习的时候觉得比较难,但只要理解了,用起来是非常方便和意义确定的。JavaScript也提供了这个this关键字,不过用起来就比经典OO语言中要"混乱"的多了。
下面就来看看,在JavaScript中各种this的使用方法有什么混乱之处?
1、在HTML元素事件属性中inline方式使用this关键字:
<div onclick="// 可以在里面使用this">division element</div>

我们一般比较常用的方法是在此使用:javascirpt: EventHandler(this),这样的形式。不过这里其实可以写任何合法的JavaScript语句,要是高兴在此定义个类也可以(不过将会是个内部类)。这里的原理是脚本引擎生成了一个div实例对象的匿名成员方法,而onclick指向这个方法。
2、用DOM方式在事件处理函数中使用this关键字:
<div id="elmtDiv">division element</div>
<script language="javascript">
var div = document.getElementById('elmtDiv');
div.attachEvent('onclick', EventHandler);

function EventHandler()
{
// 在此使用this
}
</script>

这时的EventHandler()方法中的this关键字,指示的对象是IE的window对象。这是因为EventHandler只是一个普通的函数,对于attachEvent后,脚本引擎对它的调用和div对象本身没有任何的关系。同时你可以再看看EventHandler的caller属性,它是等于null的。如果我们要在这个方法中获得div对象引用,应该使用:this.event.srcElement。
3、用DHTML方式在事件处理函数中使用this关键字:
<div id="elmtDiv">division element</div>
<script language="javascript">
var div = document.getElementById('elmtDiv');
div.onclick = function()
{
// 在此使用this
};
</script>

这里的this关键字指示的内容是div元素对象实例,在脚本中使用DHTML方式直接为div.onclick赋值一个EventHandler的方法,等于为div对象实例添加一个成员方法。这种方式和第一种方法的区别是,第一种方法是使用HTML方式,而这里是DHTML方式,后者脚本解析引擎不会再生成匿名方法
4、类定义中使用this关键字:
function JSClass()
{
var myName = 'jsclass';
this.m_Name = 'JSClass';
}
JSClass.prototype.ToString = function()
{
alert(myName + ', ' + this.m_Name);
};
var jc = new JSClass();
jc.ToString();

这是JavaScript模拟类定义中对this的使用,这个和其它的OO语言中的情况非常的相识。但是这里要求成员属性和方法必须使用this关键字来引用,运行上面的程序会被告知myName未定义。
5、为脚本引擎内部对象添加原形方法中的this关键字:
Function.prototype.GetName = function()
{
var fnName = this.toString();
fnName = fnName.substr(0, fnName.indexOf('('));
fnName = fnName.replace(/^function/, '');
return fnName.replace(/(^\s+)|(\s+$)/g, '');
}
function foo(){}
alert(foo.GetName());

这里的this指代的是被添加原形的类的实例,和4中类定义有些相似,没有什么太特别的地方。
6、结合2&4,说一个比较迷惑的this关键字使用:
function JSClass()
{
this.m_Text = 'division element';
this.m_Element = document.createElement('DIV');
this.m_Element.innerHTML = this.m_Text;

this.m_Element.attachEvent('onclick', this.ToString);
}

JSClass.prototype.Render = function()
{
document.body.appendChild(this.m_Element);
}

JSClass.prototype.ToString = function()
{
alert(this.m_Text);
};

var jc = new JSClass();
jc.Render();
jc.ToString();

我就说说结果,页面运行后会显示:"division element",确定后点击文字"division element",将会显示:"undefined"。
7、CSS的expression表达式中使用this关键字:
<table width="100" height="100">
<tr>
<td>
<div style="width: expression(this.parentElement.width);
height: expression(this.parentElement.height);">
division element</div>
</td>
</tr>
</table>

这里的this看作和1中的一样就可以了,它也是指代div元素对象实例本身。
8、函数中的内部函数中使用this关键字:
function OuterFoo()
{
this.Name = 'Outer Name';

function InnerFoo()
{
var Name = 'Inner Name';
alert(Name + ', ' + this.Name);
}
return InnerFoo;
}
OuterFoo()();

运行结果显示是:"Inner Name, Outer Name"。按我们在2中的讲解,这里的结果如果是"Inner Name, undefined"似乎更合理些吧?但是正确的结果确实是前者,这是由于JavaScript变量作用域的问题决定的,详细了解推荐参看"原来 JScript中的关键字'var'还是有文章的"一文及回复。

说了这么多JavaScript中this的用法,其实this最根本的特性还是和OO语言中的定义相吻合的。之所以有这么多看似混乱的使用方式,是因为 JavaScript语言(解释器和语言本身的内容)本身在实现上是遵循OO的(Object-based),连它的所有数据类型都是对象,也有 Object这样一个super Object。但是这个语言在运行上(runtime),就没有遵循完备的OO特点,所以就出现了this的指代混乱。
http://www.cnblogs.com/birdshome/archive/2005/03/07/95931.html

setAttribute()添加事件时

问题:给一组标签循环添加事件;
在处理这样的问题时.我原来常常这样做:


因为setAttribute()在IE中不支持对象属性.所以我只能这样写代码:
copycode:
img_c.setAttribute("id", "em_" + i + "");
if (is_ie) {
img_c.setAttribute("onclick",
function() {
alert(this.id);
}); //for IE
}
else {
img_c.setAttribute("onclick", "alert(this.id);"); //for FF
}

虽然能实现.但还是很复杂.于是改成这样:
copycode:
img_c.setAttribute("id", "em_" + i + "");
img_c.onclick = function() {
alert(this.id);
}

虽然简单.得还是觉得不好看,不知道有没有更方便简单的.

javascript面向对象(二)

面向对象基础
接着上一篇继续今天的笔记:

对象

  对象是JavaScript的基础。实际上JavaScript语言中的一切都是对象,JavaScript的多数能力也正起源于此。在其最根本的层面上,对象作为属性的集合存在,差不多类似于你在其它语言中看到的哈希的概念。程序2-19展示了创建两个带有一组属性的对象的基本示例。

 程序2-19. 创建简单对象并设置其属性的两个例子

//创建一个新对象并将其存放在obj里
var obj = new Object();
//将该对象的一些属性设置成不同的值
obj.val = 5;
obj.click = function(){
alert( "hello" );
};
//下面是等效的代码,使用了{...}式缩写,
//和定义对象属性的"名称-值"对
var obj = {
//用名称-值对设置对象属性
val: 5,
click: function(){
alert( "hello" );
}
};


实际上对象就这么回事了。然而,事情变得麻烦的地方,在于新对象(尤其是那些继承其它对象属性的对象)的创建。

对象创建

  不像大多数其它面向对象的语言,JavaScript实际上并没有类的概念。在大多数其它的面向对象语言中,你可以初始化一个特定的类的实例,但是在 JavaScript中的情况这是这样。在JavaScript中,对象能够创建新的对象,对象可以从继承自其它对象。整个概念被称为"prototypal inheritance"(原型标本继承),将在"公有方法"一节中有更多论述。

   然而,重要的是,不论 JavaScript采用哪种对象方案,总归要有一个方式来创建新的对象。JavaScript的做法是,任何一个函数也都能作为一个对象被实例化。实际上,事情听起来远比它本身更令人困惑。好比有一块生面团(相当于原始的对象),用小甜饼切割器(相当于对象构造器,使用对象的原型prototype)为其成形。
  让我们看看程序2-20中这一机制的工作的实例

程序2-20. 创建并使用一个简单的对象
copycode:
//一个简单的函数,接受一个参数name,
//并将其保存于当前上下文中
function User( name ) {
this.name = name;
}
//用指定的name创建上述函数的新实例
var me = new User( "My Name" );

//我们可以看到name已经被成为对象本身的属性
alert( me.name == "My Name" );
//而且它确实是User对象的一个新实例
alert( me.constructor == User );
//那么,既然User()只是一个函数,
//当我们这么处理它的时候,发生了什么?
User( "Test" );
//因为this上下文没有被设置,它缺省地指向全局的window对象,
//这意味着window.name将等于我们提供给它的那个name
alert( window.name == "Test" );


程序2-20说明了constructor属性的使用。这个存在于每一个对象中的属性将总是指向创建该对象的那个函数。于是,你可以方便的复制该对象,创建一个新的有共同基类和不同属性的对象。示例见程序2-21.
 程序2-21. 使用constructor属性一例

copycode:
//创建一个新的、简单的User对象(函数)
function User() {}

//创建一个新的User对象
var me = new User();

//也是创建一个新的User对象(使用上前一个对象的constructor)
var you = new me.constructor();

//我们可以看到,实际上它们的constructor是同一个
alert( me.constructor == you.constructor );


公有方法

 公有方法可以完全地被对象的上下文中的最终使用者访问。为了实现这些对于特定对象的所有实例都可用的公共方法,你需要学习一个名为"prototype"的属性。prototype简单地包含一个对象,为一个父对象的所有新副本充当对基类的引用。本质上,prototype的任何属性对该对象的所每一个实例都是可用的。创建/引用的过程给了我们一个廉价版的继承,这一点我将在第三章论及。
   由于对象的prototype 也是一个对象,就跟其它任何对象一样,你可以给它附加新的属性。附加给prototype的新的属性将成为从原来的prototype对象实例化的每个对象的一部分,有效地使得该属性成为公有的(且可为全部实例所访问)。程序2-22展示一个此类例子:

  程序2-22. 带有通过prototype附加的方法的对象的例子

copycode:
//创建一个新的User的构造器
function User( name, age ){
this.name = name;
this.age = age;
}

//为prototype对象添加一个新方法
User.prototype.getName = function(){
return this.name;
};

//为prototype对象添加另一个方法
//注意此方法的上下文将是被实例化的对象
User.prototype.getAge = function(){
return this.age;
};

//实例化一个新的User对象
var user = new User( "Bob", 44 );

//我们可以看到两个方法被附加到了对象上,有着正确的上下文
alert( user.getName() == "Bob" );
alert( user.getAge() == 44 );


私有方法

私有方法和变量只能被其它的私有方法、私有变量的特权方法(下一节将会论述)访问。这是一种定义只能在内象内部访问的代码的方式。这一技术得益于 Douglas Crockford的工作。他的网站提供了大量的详述面向对象的JavaScript的工作机制和使用方法的文档:
  JavaScript文章列表:http://javascript.crockford.com/
  文章"JavaScript中的私有成员:http://javascript.crockford.com/private.html

我们来看一个私有方法可以怎样应用中的例子,如程序2-23所示.

 程序2-23. 私有方法只能被构造函数使用的示例:
copycode:
//一个表示教室的对象构造器
function Classroom( students, teacher ) {
//用来显示教室中的所有学生的私有方法
function disp() {
alert( this.names.join(", ") );
}

//课程的数据存储在公有的对象属性里
this.students = students;
this.teacher = teacher;

//调用私有方法显示错误
disp();
}

//创建一新的教室对象
var class = new Classroom( [ "John", "Bob" ], "Mr. Smith" );

//失败,因为disp不是该对象的公有方法
class.disp();

尽管很简单,私有方法却是非常重要的,它可以在保持你的代码免于冲突同时允许对你的用户可见和可用的施以更强大的控制。接下来,我们来研究特权方法。它是你的对象中可以使用的私有方法和共有方法的联合
另外还有特权方法,静态方法.请查看原文http://bbs.blueidea.com/thread-2734050-1-1.html

弹出层居中效果的制作

问题:做一个带拖动的弹出层效果(像提示框那种)
先写了一半,明天继续奋斗:


************今天又更新一步******

点击右下角的"OPEN"




关于每一步的理解,最后解释.毕竟代码还没完全整理
被从中间扩展缓冲的效果算法难住了!

*****************OK,也不算难****************
就是让div的left和top属性随着width一起渐变就行了


遮照层效果

想了想,还是发出来吧.虽然面向对象还不是很明白.



还可以把上篇文章的弹出层居中效果的制作和本例一起加个
如下:



主要代码:
copycode:
var Class = {
min_w:960,
bint: function(r) {
$(r).style.display = "block";
$(r).style.height =Math.max(parseInt(document.documentElement.scrollHeight),parseInt(document.documentElement.offsetHeight))+ "px";
$(r).style.width = Math.max(parseInt(document.body.offsetWidth),Class.min_w)+"px";
},
x: function(r,d) {
for (i = 1; i < r; i++) {
var c = document.createElement("div");
c.innerHTML = i;
$(d).appendChild(c);
}
},
res: function(r,wr) {
$(r).style.width = Math.max(parseInt(document.body.offsetWidth),Class.min_w)+"px";
$(r).style.height =Math.max(parseInt(document.documentElement.scrollHeight),parseInt(document.documentElement.offsetHeight))+ "px";
}

};


代码全自己一个弄的.如有错误请大家指正.谢谢!