首页 > 编程语言 >你不知道的 JavaScript - “this”

你不知道的 JavaScript - “this”

时间:2023-08-28 14:04:12浏览次数:71  
标签:函数 demo button JavaScript value foo type 知道


JavaScript 里的 this 到底指得是什么?很多人都会告诉你 this 指的是当前对象。这样理解对么?在大多数情况下确实没错。比如我们经常会在网页上写这样的 JavaScript:

 

< 
  input  
  type 
  ="submit" 
   value 
  ="提交" 
   onclick 
  ="this.value='正在提交数据'" 
    
  />

这里的this显然指的是当前对象,即这个提交按钮。通常,我们使用this的情况都与此类似。但是有什么情况不是这样的呢?

大家看看这个例子:

 

var    foo  
  = 
    
  function 
  ()  
  
   {
    console.log(this);
}   
foo();
   new 
   foo();

比较一下 foo() 和 new foo() 的运行结果,你会发现,前者 this 指向的并非 foo 本身,而是当前页面的window对象,而后者才真正的指向foo。这是为什么呢?

其实这牵涉到JavaScript的一条重要特性,就是所谓的“闭包”。闭包这个概念说复杂也不复杂,但也不是简单到能用一两句话说清。偶会在以后的文章中深入探讨这个Javascript 最重要的特性。现在,我要告诉大家的是,因为闭包的存在,JavaScript中的作用域变得相当重要。

所谓的作用域,简单的说,就是创建一个函数时在什么环境下创建的。而this变量的值,如果没有指定的话,就是函数当前的作用域。

 

在前面的例子里,foo() 函数是在全局作用域(这里就是window对象),所以this的值是当前的window对象。而通过 new foo() 这样的形式,其实是创建了一个foo()的副本,并在这个副本上进行的操作,所以这里的this就是foo()的这个副本。

 

这样讲可能有点抽象,大家来看个实际的例子:

<   input type="button"   id 
  ="aButton" 
   value 
  ="demo" οnclick="" /> 
  
   <   script  
  type 
  ="text/javascript" 
  > 
  
   
function demo() 
{
    this.value = Math.random();
}
   </   script 
  >

 

如果直接调用demo() 函数,程序就会报错,因为demo函数是在window对象中定义的,所以demo的拥有者(作用域)是window,demo的this也是window。而window是没有value属性的,所以就报错了。

你不知道的 JavaScript -  “this”_HTML

如果我们通过创建副本的方式,将这个函数的副本添加到一个HTML元素,那么他的所有者就成了这个元素,this也指代了这个元素:

 

document.getElementById(   "   aButton   " 
  ).onclick  
  = 
   demo;

 

这样就将aButton的onlick属性设置为demo()的一个副本,this也指向了aButton。

你不知道的 JavaScript -  “this”_prototype_02

你甚至可以为多个不同的HTML元素创建不同的函数副本。每个副本的拥有者都是相对应的HTML元素,各自的this也都指向他们的拥有者,不会造成混乱。

你不知道的 JavaScript -  “this”_作用域_03

 

但是,如果你这样定义某个元素的onlick事件:

 

<    input     type    ="button"     id 
   ="aButton" 
    value 
   ="demo" 
    onclick 
   ="demo()" / 
   >

 

点击这个button之后,你会发现,程序又会报错了——this又指向了window!

其实,这种方法并没有为程序创建一个函数,而只是引用了这个函数。

具体看一下区别吧。

 

使用创建函数副本的方法:

 

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 
   
<    input     type    ="button"     id    ="aButton" 
    value 
   ="demo" 
     
   /> 
   
    <    script     type    ="text/javascript"    > 
   
    
var button = document.getElementById("aButton");
function demo() 
{
    this.value = Math.random();
}
button.notallow= demo;
alert(button.onclick);
    </    script    >

得到的输出是:

function     demo()     
    {
    this.value = Math.random();
}  
 
使用函数引用的方法:
 
      
<    input     type    ="button"     id    ="aButton"     value    ="demo" 
    onclick 
   ="demo()" 
     
   /> 
   
    <    script     type    ="text/javascript"    >    
    
var button = document.getElementById("aButton");
function demo() 
{
    this.value = Math.random();
}
alert(button.onclick);
    </    script    >  
 
得到的输出是:
 
      
function onclick() {
    demo();
}

这样就能看出区别了吧。函数引用的方式中,onclick事件只是直接调用demo()函数,而demo()函数的作用域仍旧是window对象,所以this仍然指向window。

你不知道的 JavaScript -  “this”_ViewUI_04

 

这样就又引出了一个问题:既然函数副本这么好用,为什么还需要函数引用的方法呢?答案是性能。每新建一个函数的副本,程序就会为这个函数副本分配一定的内存。而实际应用中,大多数函数并不一定会被调用,于是这部分内存就被白白浪费了。而使用函数引用的方式,程序就只会给函数的本体分配内存,而引用只分配指针,这样效率就高很多。程序员么,节约为主,恩

你不知道的 JavaScript -  “this”_作用域_05

所以我们来看一个更好的解决方案:

 

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 
   
<    script     type    ="text/javascript"    >    
    
function demo(obj) 
{
    obj.value = Math.random();
}
    </    script    >    
    <    input     type    ="button"     value    ="demo"     onclick    ="demo(this)"      
   /> 
   
    <    input     type    ="button"     value    ="demo"     onclick    ="demo(this)"      
   /> 
   
    <    input     type    ="button"     value    ="demo"     onclick    ="demo(this)"      
   />

 

这样,效率和需求就都能兼顾了。

 

最后再多讲一句:在前面的文章里,我特别强调了“如果没有指定this的话”。其实this是可以指定的。Function对象有两个方法:call()和apply()。这两个方法都支持指定一个函数中的this。有兴趣的话您可以去查一下Javascript的手册,看看这两个函数都是干什么用的。而我们经常用的 new foo() 可以用以下这段伪代码来描述:

 

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 
   
function     new (somefunction)     
    {
    var args = [].slice.call(arguments, 1);
    somefunction.prototype.constructor = somefunction;
    somefunction.apply(somefunction.prototype, args);
    return somefunction.prototype;
}

现在明白了,在本文开头的第一个例子里,new foo() 的 this 为什么是 foo 了吧

你不知道的 JavaScript -  “this”_prototype_06

标签:函数,demo,button,JavaScript,value,foo,type,知道
From: https://blog.51cto.com/u_16237557/7263418

相关文章

  • JavaScript FSO属性大全
     什么是FSO?FSO即FileSystemObject文件系统对象,是一种列表Windows磁盘目录和文件,对目录和文件进行删除、新建、复制、剪切、移动等操作的技术。使用FSO网站的好处:直接读取目录下的文件和子目录,方便维护,如需要添加任何内容,将文件放在相应的目录下即可;FSO网站类似Window......
  • Javascript中this的用法小结
    1.概述this是面向对象语言中的一个重要概念,在JAVA,C#等大型语言中,this固定指向运行时的当前对象。但是在javascript中,由于javascript的动态性(解释执行,当然也有简单的预编译过程),this的指向在运行时才确定。这个特性在给我们带来迷惑的同时也带来了编程上的......
  • Javascript Print(*)
    1.实现打印功能1)ExecWB()通过脚本程序来调用IE菜单下面的打印命令。实现的代码如下:<scriptlanguage="javascript">functionprintsetup(){//打印页面设置wb.execwb(8,1);}functionprintpreview(){//打印页面预览wb.execwb(7,1);......
  • Javascript压缩工具
    javascriptcompressor.com(在线压缩)shrinksafe.dojotoolkit.org(在线文件压缩)dean.edwards.name/packer(在线压缩)YUICompressor(使用命令行来压缩,需要JAVA虚拟机来运行压缩程序 有个压缩比更高的,是个要注册的软件...javascriptObfuscatorhttp://www.javascript-source.......
  • HTML5你必须知道的28个新特性
    HTML5有很多的新功能.新代码.非常不错.现在总结一下.仅供参考1.新的Doctype尽管使用<!DOCTYPEhtml>,即使浏览器不懂这句话也会按照标准模式去渲染2.Figure元素用<figure>和<figcaption>来语义化地表示带标题的图片<figure><imgsrc=”path/to/image”alt=”Aboutimage”......
  • JavaScript-比较运算符
    概述比较运算符用于比较两个值的大小,然后返回一个布尔值,表示是否满足指定的条件。2>1//true上面代码比较2是否大于1,返回true。注意,比较运算符可以比较各种类型的值,不仅仅是数值。一共提供了8个比较运算符。>大于运算符<小于运算符<=小于或等于运算符>=大于或等于运算符==......
  • JavaScript 基础知识
    avaScript基础知识以前的概述:网络入门下一个JavaScript是一种为您的网站添加交互性的编程语言。这种情况发生在游戏中、按下按钮或在表单上输入数据时的响应行为中;具有动感的造型;动画等。本文帮助您开始使用JavaScript并加深您对可能性的理解。什么是JavaScript?Ja......
  • JavaScript的变量提升
    参考资料:https://time.geekbang.org/column/article/126339目录变量提升变量形式声明的函数变量提升导致的问题变量被覆盖变量不被销毁避开变量提升引入let和const关键字块级作用域变量提升是在代码执行时,把变量和函数的声明部分提升到代码开头的行为,变量被提升后,会被默认设置......
  • JavaScript中的不可变原始值和可变对象引用
    在JavaScript中,原始值(undefined、null、布尔值、数字和字符串)与对象(包括数组和函数)之间存在着根本的区别。原始值是不可变的,意味着它们的值无法改变。这对于数字和布尔值很容易理解:修改它们的值是没有意义的。然而,对于字符串来说,这可能会稍微不太直观。由于字符串类似于字符数组,可......
  • 【LeetCode动态规划#17】知道秘密的人,维护多个dp数组
    知道秘密的人数在第1天,有一个人发现了一个秘密。给你一个整数delay,表示每个人会在发现秘密后的delay天之后,每天给一个新的人分享秘密。同时给你一个整数forget,表示每个人在发现秘密forget天之后会忘记这个秘密。一个人不能在忘记秘密那一天及之后的日子里分享......