搜索
首页web前端js教程Javascript中的this对象

Javascript中的this对象

Jul 07, 2018 am 11:06 AM

 这篇文章主要介绍了关于Javascript中的this对象,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

对于this的使用,我们最常遇到的主要有,在全局函数中,在对象方法中,call和apply时,闭包中,箭头函数中以及class中;

我们知道this对象是在运行时基于函数的执行环境绑定的,在调用函数之前,this的值并不确定,因此this会在代码执行过程中引用不同的对象。哪个对象实例调用this所在的函数,那么this就代表哪个对象实例。

1.    全局函数

       在全局函数中,this等于window;

var name = "Tina";function sayName() {
    alert(this.name);
}
person();//Tina

       在这里,由于函数person()是在全局环境中执行的,也是在全局作用域中window对象调用的person();故此时的this便指向window对象。而当把这个函数赋给对象o并调用o.sayName()时,this引用的是对象o,因此对this.name的求值就变成了对o.name求值。 

 name = "Tina"

2. 对象方法

       当函数被作为某个对象的方法调用时,this等于那个对象;

var name="Tina";var obj={
      name="Tony",
      getName: function() {
            alert(this.name);
      }
};
obj.getName();//"Tony"

3.call()和apply()和bind()

      我们知道,call(ctx, parm1,parm2,parm3...)和apply(ctx,[parms])的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值;

function sum(num1, num2)  {      return num1+num2;
}function callSum1(num1, num2) {      return sum.apply(this, [num1, num2]);
}function callSum2(num1,num2) {      return sum.call(this, num1, num2);
}
alert(callSum1(10, 10)); //20alert(callSum2(10, 10));//20

      在上面的例子中,callSum1()和callSum2()在执行函数sum()时传入了this作为this值(因为是在全局作用域中调用的,所以传入的就是window对象);事实上,call和apply最强大之处是能够扩充函数赖以运行的作用域;来看下面的例子:

window.color="red";var o={ color: "blue"};function sayColor() {
      alert(this.color);
}
sayColor();//"red"sayColor.call(this);//"red"sayColor.call(window);//"red"sayColor.call(o);//"blue"

      bind()方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。例如:

window.color="red";var o={ color: "blue" };function sayColor() {
    alert(this.color);
}var objsayColor = sayColor.bind(o);
objsayColor();//"blue"

       另一个使用场景是函数绑定,函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数,该技巧常常和回调函数与事件处理程序一起使用,以便在将函数作为变量传递的同时保留代码执行环境。

var handler = {
      message: "Event handled",
      handleClick : function(event) {
            alert(this.message);
      }
};var btn = document.getElementById("my_btn");
btn.addEventListener("click", handler.handleClick, false);

      当按下该按钮时,就调用该函数,显示一个警告框,虽然貌似警告框应该显示Event handled,然而实际上显示的是undefined。原因在于没有保存handler.handleClick()的执行环境,所以this对象最后指向了DOM按钮而非handler(在IE8中,this指向window)。一种方法,可以使用一个闭包来修正这个问题。

var handler = {
      message: "Event handled",
      handleClick : function(event) {
            alert(this.message);
      }
};var btn = document.getElementById("my_btn");
btn.addEventListener("click", function(event){
      handler.handleClick(event);
}, false);

      这个解决方案在onclick事件处理程序内使用了一个闭包直接调用handler.handleClick(),当然,这是特定与本段代码的解决方案。我们知道,创建多个闭包可能会令代码变得难以理解和调试。因此,很多JS库实现了一个可以将函数绑定到指定环境的函数,这个函数一般叫bind();ECMAScript 5为所有函数定义了一个原生的bind()方法,它的使用方式如下:

var handler = {
      message: "Event handled",
      handleClick : function(event) {
            alert(this.message+":"+event.type);
      }
};var btn = document.getElementById("my_btn");
btn.addEventListenr("click", handler.handleClick.bind(handler), false);

      一个简单的bind()函数接受一个参数和一个环境,并返回一个在给定环境中调用给定函数的函数,并且将所有参数原封不动地传递过去。语法如下:

function bind(fn, context) {      
return function() {            
return fn.apply(context, arguments);
      };
}

      这个函数在bind()中创建了一个闭包,闭包使用apply调用传入的函数,并给apply传递context对象个arguments对象数组,这里的arguments对象是内部函数(匿名函数)的,而非bind()的参数。当调用返回的函数时,它会在给定环境中执行被传入的函数并给出所有参数。

      原生的bind()方法和前面自定义的bind()方法类似,都是要传入作为this值的对象。它们主要用于事件处理程序以及setTimeout()和setInterval()。bind绑定在react事件处理中也常常和箭头函数一样起到绑定this的效果。

4. 闭包

      有时候,由于编写闭包的方式不同,在闭包中使用this对象可能会导致一些问题;

var name = "The window";var object = {
      name: "My Object",
      getNameFunc: function() {            
      return function() {                  
      return this.name;
            };
      }
};
alert(object.getNameFunc()());//"The window"

      由于getNameFunc()返回一个函数,因此调用object.getNameFunc()()就会立即调用它返回的函数,结果就是返回一个字符串"The window",即全局变量的值,此时匿名函数没有取得其包含作用域(外部作用域)的this对象。原因在于内部函数在搜索两个特殊变量this和arguments时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。这时,只需把把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了。

var name = "The window";var object = {
      name: "My Object",
      getNameFunc: function() {            
      var that = this;            
      return function() {                  
      return that.name;
            };
      }
};
alert(object.getNameFunc()());//"My Object"

//节流function throttle(fn, delay) {      
var previous = Data.now();      
return function() {             
var ctx = this;             
var args = arguments;             
var now = Data.now();             
var diff = now-previous-delay;              
if(diff>=0) {
                    previous = now;
                    setTimeout(function() {
                         fn.apply(ctx, args);
                    }, delay);
              }
       };
}

5. 箭头函数

      我们知道,箭头函数有几个需要注意的点:

      (1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象;

      (2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误;

      (3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用rest参数代替;

      (4)不可以使用yield命令,因此箭头函数不能用作Generator函数;

      这里我们只谈论第一点;this对象的指向是可变的,但在箭头函数中,它是固定的;

function foo() {
      setTimeout(() => {
          console.log('id: ', this.id);
      }, 100);
}var id=21;
foo.call({id: 31});//id: 31

      上述代码中,setTimeout是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它真正加入到执行栈后还要等到100毫秒后才会执行,如果是普通函数,此时的this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id:31})所以输出的是id: 31;

      箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。下面是另一个例子:

function Timer() {      this.s1 = 0;      this.s2 = 0;
      setInterval(() => this.s1++, 1000);
      setInterval(function() {            this.s2++;
      }, 1000);
}var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);//s1: 3setTimeout(() => console.log('s2: ', timer.s2), 3100);//s2: 0

      上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100毫秒后,timer.s1被更新了3次,timer.s2一次都没更新。

      箭头函数可以让this指向固定化,这种特性很有利于封装回调函数。下面代码将DOM事件的回调函数封装在一个对象里面。

var handler = {
      id: '123456',
      init: function() {
            document.addEventListener('click',
                event => this.doSomething(event.type), false);
      },
      doSomething: funcition(type) {
            console.log('Handling ' + type + ' for ' + this.id);
      }
};

      上面代码的init方法中,使用了箭头函数,这导致这个箭头函数里面的this,总是指向handler对象。否则,回调函数运行时,this.doSomething这一行会报错,因为此时this指向document对象。this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码的this。正是因为它没有this,所以也就不能用作构造函数。由于箭头函数没有自己的this,所以当然不能用call()、apply()、bind()改变this的指向。

6. class

      类的方法内部如果含有this,它默认指向类的实例。

class Logger {    /*constructor() {
        this.printName = this.printName.bind(this);
    }*/
    printName(name = 'Nicolas') {        this.print(`Hello ${name}`);
    }
    print(text) {
        console.log(text);
    }
}
const logger = new Logger();
const { printName } = logger;
printName();

      上面代码中,printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境,因为找不到print方法而导致报错。一种简单的解决方法就是在构造函数中绑定this。而另一种方法是使用箭头函数:

class Logger {
    constructor() {        this.printName = (name='Nicolas') => {            this.print(`Hello ${name}`);
    }
    print(text) {
        console.log(text);
    }
}
const logger = new Logger();
const { printName } = logger;
printName();

      还有一种方法是使用Proxy,获取方法的时候,自动绑定this。

function selfish (target) {
  const cache = new WeakMap();
  const handler = {
    get (target, key) {
      const value = Reflect.get(target, key);      if (typeof value !== 'function') {        return value;
      }      if (!cache.has(value)) {
        cache.set(value, value.bind(target));
      }      return cache.get(value);
    }
  };
  const proxy = new Proxy(target, handler);  return proxy;
}
const logger = selfish(new Logger());

 以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

foreach, for in, for of 之间的异同

Vue+Electron实现简单桌面应用

JS定时器和单线程异步特性

以上是Javascript中的this对象的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
Python vs. JavaScript:学习曲线和易用性Python vs. JavaScript:学习曲线和易用性Apr 16, 2025 am 12:12 AM

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python vs. JavaScript:社区,图书馆和资源Python vs. JavaScript:社区,图书馆和资源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C到JavaScript:所有工作方式从C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器