手机版

Javascript这个指针

时间:2021-11-25 来源:互联网 编辑:宝哥软件园 浏览:

前言

Javascript是一种基于对象的动态语言,即一切都是对象,一个典型的例子就是函数也被视为普通对象。Javascript可以通过一定的设计模式实现面向对象的编程,而这个“指针”是实现面向对象的一个非常重要的特性。然而,这也是Javascript中一个容易被理解和错误使用的特性。尤其是对于长期接触静态语言的同志。00-1010我们先来看一个最简单的例子:脚本类型=' text/JavaScript ' var name=' Kevin yang ';函数sayHi(){ alert('你好,我叫' name ');} SayHi();脚本很简单,我们定义一个全局字符串对象名和一个函数对象sayHi。跑步会弹出一个问候对话框,“你好,我叫杨凯文”。我们稍微修改了一下这段代码:脚本类型=' text/JavaScript ' var name=' Kevin Yang ';函数sayHi(){ alert ('Hello,我叫' this . name ');} SayHi();脚本代码和之前的代码的区别在于,sayHi函数以此为前缀。使用名称时。运行结果同上。这表明this.name也指全局名称对象。一开始,我们并没有说函数也是普通对象,可以作为普通变量。让我们更改上面的代码:脚本类型=' text/JavaScript ' var name=' Kevin Yang ';函数sayHi(){ alert ('Hello,我叫' this . name ');} var person={ }person.sayHello=sayHiperson . say HellO();脚本这次,我们创建了一个全局对象person,并将sayHi函数对象分配给person对象的sayHello属性。运行结果如下:image

这次问候的内容有点无意义,我们发现这个. name已经变得没有定义了。这表明在sayHello函数内部执行时,无法再找到this.name对象。如果我们重新定义person对象,并为其添加一个name属性,会怎么样?var person={ name : ' Mary ' };运行代码发现,打招呼的“人”变了:image

你看到什么不对吗?

示例说明

在Javascript中,这个指针代表执行当前代码的对象的所有者。在上面的例子中,我们可以看到,我们第一次定义了一个全局函数对象sayHi并执行了这个函数,而这个关键字是在函数内部使用的,所以执行这一行代码的对象是sayHi(一切都是对象的体现),而sayHi是在全局范围内定义的。事实上,Javascript中所谓的全局对象只不过是根对象窗口下定义的一个属性。因此,sayHi的所有者是窗口对象。也就是说,在全局范围下,可以使用name直接引用这个对象,也可以使用window.name引用同一个对象.因此,这个. name可以翻译成window.name.让我们看看第二个例子。我们定义了一个人的对象及其sayHello属性,这样它就指向了sayHi全局对象。这时我们运行person.sayHello时,这段代码的对象是sayHello(其实sayHi和sayHello就像两个指针,它们指向的对象其实是一样的),sayHello对象的所有者就是person。第一次没有亲自命名属性,所以弹出的对话框是this.name指的是未定义的对象(所有在Javascript中声明但未定义的变量都指向未定义的对象);第二次我们在定义person时添加了name属性,那么这个. name自然指向我们定义的字符串。了解以上内容后,我们将最后一个示例转换为面向对象的代码。脚本类型=' text/JavaScript ' var name=' Kevin Yang ';函数sayHi(){ alert ('Hello,我叫' this . name ');}函数Person(name){ this . name=name;} person . prototype . SayHello=SayHi;var marry=新人(“结婚”);marry . say HellO();var kevin=新人(' Kevin ');Kevin . SayHello();脚本在上面的代码中,我们定义了一个Person的“类”(实际上是一个对象),然后在这个类的原型中定义了sayHello属性(相当于c语言中静态成员变量的概念),使其指向全局sayHi对象。运行代码,我们可以看到玛丽和凯文都成功地迎接了我们。这段代码中有两件事需要考虑。一个是新的。我们很熟悉它,但是new在这里到底做了什么?另一个是,在这里执行sayHello的时候,为什么这个指针可以正确指向marry和kevin objects呢?让我们重新“翻译”一下上面定义的“类”和实例化类对象的操作:脚本类型=' text/JavaScript ' var name=' Kevin Yang ';函数sayHi(){ alert ('Hello,我叫' this . name ');}函数Person(name){ var this;this.name=name归还这个;} person . prototype . SayHello=SayHi;var Marry=Person(' Marry ');marry . say HellO();var kevin=人(' Kevin ');Kevin . SayHello();当然,脚本不能正确执行,但它可以帮助您更好地理解过程。当我们使用new关键字实例化一个“类”对象时,Javascript引擎将在对象内部定义一个新对象,并将其存储在这个指针中。在这个对象中使用这个的所有代码实际上都指向这个新对象。如果this.name=name,则参数中的name对象实际上被分配给这个新创建的对象。函数执行后,Javascript引擎会把对象返回给你,所以Mary变量得到的对象名称是“Mary”,而kevin变量得到的对象名称属性确实是“Kevin”。00-1010了解了这个指针之后,我们再来看看一些容易误用这个指针的情况。

示例1——脚本类型=' text/JavaScript '函数sayhi () {alert('当前单击的元素是' this . tagname ');}脚本输入id=' btntest ' type=' button ' value=' click on me ' onclick=' sayHi()'在这段代码中,我们绑定了button的click事件,并期望在弹出的对话框中打印被点击元素的标签名。但运行结果是:image

也就是说,这个指针不指向输入元素。这是因为当对内联绑定Dom元素使用事件处理程序时,实际上相当于执行以下代码:脚本类型=' text/JavaScript ' document . getelementbyid(' btntest ')。onclick=function(){ say hi();}脚本在这种情况下,sayHi函数对象的所有权尚未转移,仍然属于window。有了以上一套指导原则,我们就能很好地理解为什么this.tagName是未定义的。如果我们想引用元素本身呢?我们知道,onclick函数属于btnTest元素,所以在这个函数内部,这个指针指向这个Dom对象,所以我们只需要把这个作为参数传递给sayHi。脚本类型=' text/JavaScript '函数sayhi (El) {alert('当前单击的元素是' El . tagname ');}脚本输入id=' btntest ' type=' button ' value=' click on me ' onclick=' sayHi(this)'等效代码如下:脚本类型=' text/JavaScript ' document . getelementbyid(' btntest ')。onclick=function(){ say hi(this);}脚本示例2——由于临时变量脚本类型=' text/JavaScript ' var utility={ decode 3360 function(str){ return escape(str)},此指针丢失;},getcookie :函数(键){//.省略提取cookie字符串的代码var值='我是cookie ';返回this.decode(值);} };警报(实用程序。getCookie ('identity ')脚本当我们编写稍微大一点的Js库时,通常会自己封装一个utility类,然后将一些常用的函数作为Utility类的属性,比如客户端经常使用的getCookie函数和解码函数。如果每个功能相互独立,就很容易了。问题是函数有时会相互引用。例如,上面的getCookie函数将解码从document.cookie提取的字符串,然后返回它。如果我们通过Utility.getCookie调用它,那么就没有问题了。我们知道getCookie中的这个指针指向Utility对象,而Utility对象包含解码属性。代码可以成功执行。但是有人不小心这样使用了Utility对象?脚本类型=' text/JavaScript '函数show user identity(){//将getCookie函数保存到一个局部变量,因为下面经常使用var getCookie=utility . getCookie;alert(getCookie('身份'));} showuser identity();脚本将在此时运行代码时抛出异常“this.decode不是函数”。使用我们上面提到的指导原则,很容易理解,因为Utility.getCookie对象此时被分配给了临时变量getCookie,而临时变量属于window对象——,不能被外界直接引用,只能被Javascript引擎看到。因此,getCookie函数中的这个指针指向窗口对象,而窗口对象没有定义解码函数对象,所以会抛出这个异常。这个问题是由于临时变量的引入导致这个指针的转移引起的。这个问题有几种解决方法:不引入临时变量,每次使用Utility.getCookie调用。getCookie函数使用Utility.decode显式引用decode对象,但不通过此指针隐式引用(如果Utility是实例化对象,即它是通过new生成的,则此方法不可用。)使用Funtion.apply或Function.call函数指定此指针。前两个容易理解,第三个需要提及。因为这个指针的指针很容易被转移丢失,所以Javascript提供了两个类似的函数,apply和call,允许函数在调用时显式地重新指定这个指针。修改后的代码如下:脚本类型=' text/JavaScript '函数show user identity(){//将getCookie函数保存到局部变量,因为下面经常使用var getCookie=utility . getCookie;警报(getCookie.call(Utility,‘identity’));alert(getCookie.apply(Utility,[' identity ']);} showuser identity();Scriptcall和apply只有语法上的区别,没有功能上的区别。

示例3——当函数传递参数时,该指针丢失。我们先来看一个问题代码:脚本类型=' text/JavaScript ' var person={ name : ' Kevin yang ',sayhi 3360 function(){ alert(' hello,我是' this . name ');} } setTimeout(person.sayHi,5000);脚本代码期望在访问者进入页面五秒钟后向他们问好。setTimeout函数接收一个函数作为参数,并在指定的触发时间执行它。然而,当我们等待5秒钟时,弹出的对话框显示this.name未定义。其实这个问题和上一个例子类似,是临时变量引起的。当我们执行一个函数时,如果函数有参数,那么此时Javascript引擎会创建一个临时变量,并将传递的参数复制到这个临时变量中(注意,Javascript全部是值传递,没有引用传递的概念)。也就是说,整个过程和我们上面定义的getCookie的临时变量是一样的,然后把Utility.getCookie赋给这个临时变量。只是在这个例子中,很容易忽略临时变量导致的bug。

判别this指针的指导性原则

很多框架都解决了这个指针因为函数作为参数传递而丢失的问题。Prototype的解决方案——在传递参数之前使用bind方法封装函数,并返回封装对象script type=' text/JavaScript ' var person={ name : ' Kevin Yang ',sayhi 3360 function(){ alert(' hello,I ' this . name);} } var boundFunc=person . SayHi . bind(person,person . SayHi);setTimeout(BoundFuc,5000);事实上,scriptbind方法的实现使用了Javascript的另一个高级特性,——闭包。让我们看看源代码:function bind(){ if(arguments . length 2 arguments[0]==undefined)返回这个;var __method=this,args=$A(参数),object=args . shift();return function(){ return _ _ method . apply(object,args . concat($ A(arguments)));}}首先将这个指针存储在函数内部的临时变量中,然后在返回的函数对象中引用这个临时变量形成闭包。微软的Ajax库提供了——的方案来构建委托对象脚本类型=' text/JavaScript ' var person={ name 3360 ' Kevin Yang ',sayhi 3360 function(){ alert(' hello,我是' this . name ');} } var boundFunc=function . create delegate(person,person . sayhi);setTimeout(BoundFuc,5000);脚本本质上和原型是一样的。著名的Extjs库的解决方案和微软的是一样的。

版权声明:Javascript这个指针是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。