一、什么是this?

this是JavaScript语言的一个关键字,它是函数运行时在函数体内部自动生成的一个对象,只能在函数体内部使用。函数的不同使用场合,this的指向不同。

在ES5中,this永远指向最终调用它的对象。

  1. 1
  2. 这里最终调用函数a的对象是全局window,相当于window.a()。
  3. 所以this指向windowthis.name的值为全局变量name的值 'windowsName'
  4.  
  5. var name = "windowsName";
  6. function a () {
  7. var name = "Cherry";
  8. console.log(this.name); // windowsName
  9. console.log(this); // [object Window]
  10. }
  11. a();
  12. console.log(this) // [object Window]
  1. 2
  2. a.fn()调用函数fn的最终对象是athis指向对象a,所以最终的name值是'skillnull'
  3. window.a.fn()调用函数fn的最终对象是athis指向a,所以最终的name值是'skillnull'
  4. 注:由于window下的变量和方法访问和调用的时候可以省略window,所以a.fn() === window.a.fn()。
  5. b()调用函数fn的最终对象是windowthis指向window,所以最终的name值是'windowsName'。这里将a.fn赋值给变量b的时候并没有调用fn
  6.  
  7. var name = "windowsName";
  8. var a = {
  9. name: "skillnull",
  10. fn: function () {
  11. console.log(this.name);
  12. }
  13. }
  14. a.fn(); // skillnull
  15. window.a.fn(); // skillnull
  16.  
  17. var b = a.fn;
  18. b(); // windowsName

二、如何改变this的指向?

  • 使用 ES6 的箭头函数
    箭头函数的 this 始终指向函数定义时的 this,而非执行时。

    1. 3
    2. 注:若setTimeout推迟执行的函数是某个对象的方法,那么该方法中的this关键字将指向全局环境。
    3. 由此可以看出a.fn2()中被setTimeout推迟执行的函数的最终调用对象是windowthis指向window
    4. window中没有fn1方法,所以最终结果为错误信息:this.fn1 is not a function
    5. a.fn3()中被setTimeout推迟执行的函数使用了箭头函数,此时的this指向函数定义时的this,即a,所以最终结果为:skillnull
    6. a.fn4()中的函数没有被setTimeout推迟执行,最终对象仍为a,此时的this指向a,所以最终结果为:skillnull
    7.  
    8. var name = "windowsName";
    9. var a = {
    10. name: "skillnull",
    11. fn1: function () {
    12. console.log(this.name)
    13. },
    14. fn2: function () {
    15. // console.log(this) // a
    16. setTimeout(function () {
    17. // console.log(this) // [object Window]
    18. this.fn1()
    19. }, 100);
    20. },
    21. fn3: function () {
    22. setTimeout(() => {
    23. // console.log(this) // a
    24. this.fn1()
    25. }, 100);
    26. },
    27. fn4: function () {
    28. this.fn1()
    29. }
    30. };
    31. a.fn2() // this.fn1 is not a function
    32. a.fn3() // skillnull
    33. a.fn4() // skillnull
  • 在函数内部使用 that = this
    1. 如果上面例子中的fn2中使用that = this改变一下this的指向,此时that属于fn2的内部变量,指向a,所以最终结果为:skillnull
    2. fn2: function () {
    3. var that = this;
    4. setTimeout(function () {
    5. // console.log(that) // a
    6. that.fn1()
    7. }, 100);
    8. }
  • new 实例化一个对象

    如果函数调用前使用了 new 关键字, 则是调用了构造函数。这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象。

    new实例化一个对象的过程如下:
    1.创建一个空对象 obj;
    2.将新创建的空对象的隐式原型指向其构造函数的显示原型。
    3.使用 call 改变 this 的指向
    4.如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。

    1. 伪代码表示:
    2. var a = new myFunction("Li", "Yafei");
    3. new myFunction {
    4. var obj = {};
    5. obj.__proto__ = myFunction.prototype;
    6. var result = myFunction.call(obj, "Li", "Yafei");
    7. return typeof result === 'obj' ? result : obj;
    8. }
  • 使用 apply、call、bind
    1. 4
    2. callapplybind都可以更改this的指向,三者作用相同。
    3. 由于a.fn赋值给全局变量b的时候没有执行,上面已经说过,此时的this指向widnow,调用b('skill', 'null')的结果为:i am skillnull
    4. 而在调用方法b的时候使用callapplybind,将此时的this指向a,所以最终结果是:i am not skillnull
    1. var name = 'i am '
    2. var a = {
    3. name: "i am not ",
    4. fn: function (a, b) {
    5. console.log(this.name + a + b)
    6. }
    7. }
    8.  
    9. var b = a.fn;
    10. b('skill', 'null') // i am skillnull
    11. b.call(a, 'skill', 'null') // i am not skillnull
    12. b.apply(a, ['skill', 'null']) // i am not skillnull
    13. b.bind(a, 'skill', 'null')() // i am not skillnull

三、call、apply、bind 和 this 的关系

从上面的文章可以看出来,其实call、apply、bind最常用的用途是更改this指向。

四、call、apply、bind三者的区别

call和apply不同之处主要在于参数的形式,call参数是一个列表,apply参数是一个数组。
       而bind会创建一个新函数,需要手动调用,bind的参数形式和call相同。

注:如果当前函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象)。

简述this,call,apply,bind之间的关系的更多相关文章

  1. 数组去重,call、apply、bind之间的区别,this用法总结

    一.数组去重,直接写到Array原型链上. //该方法只能去除相同的数字 不会去判断24和'24'是不同的 所有数字和字符串数字是相同是重复的 Array.prototype.redup=functi ...

  2. javascript-this,call,apply,bind简述2

    上节我们一起研究了this这个小兄弟,得出一个结论,this指向调用this所在函数(或作用域)的那个对象或作用域.不太理解的朋友可以看看上节的内容,这次我们主要探讨一下call(),apply(), ...

  3. javascript-this,call,apply,bind简述1

    最近在系统的学习面向对象方面的知识,遇到的最大拦路虎就数this的指向,call,apply,bind函数的使用,单独抽出一天时间把这几个烦人的家伙搞定,去学习更深入的内容. 首先介绍一下this的一 ...

  4. angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。

    最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...

  5. call(),apply(),bind()与回调

    1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...

  6. [工具] slf4j-api、slf4j-log4j12以及log4j之间的关系

    几乎在每个jar包里都可以看到log4j的身影,在多个子工程构成项目中,slf4j相关的冲突时不时就跳出来让你不爽,那么slf4j-api.slf4j-log4j12还有log4j是什么关系?     ...

  7. 你不知道的JavaScript--Item9 call(),apply(),bind()与回调

    1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...

  8. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    [Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...

  9. Java 8-Lambda表达式、方法引用、标准函数接口与流操作、管道操作之间的关系

    1.Lambda表达式与接口之间的关系 只要Lambda表达式的声明形式与接口相一致,在很多情况下都可以替换接口.见如下代码 Thread t1 = new Thread(new Runnable() ...

随机推荐

  1. Java EE JSP内置对象及表达式语言

    一.JSP内置对象 JSP根据Servlet API规范提供了一些内置对象,开发者不用事先声明就可使用标准变量来访问这些对象. JSP提供了9种内置对象: (一).request 简述: JSP编程中 ...

  2. CsvHelper文档-4映射

    CsvHelper文档-4映射 类映射 有时候你的类成员和csv的header不一定对应,有时候你的csv文件根本就没有header行,你需要特别制定一个成员的index,你不能依靠.net中默认的顺 ...

  3. ES数据备份到HDFS

    1.准备好HDFS(这里我是本机测试) 2.es 安装repository-hdfs插件 (如es为多节点需在每个节点都安装插件) elasticsearch-plugin install repos ...

  4. Machine Learning笔记整理 ------ (一)基本概念

    机器学习的定义:假设用P来评估计算机程序在某任务类T上的性能,若一个程序通过利用经验E,使其在T中任务获得了性能改善,我们则说关于任务类T和P,该程序对经验E进行了学习(Mitchell, 1997) ...

  5. pyextend库-unpack列表集合字符串解包函数

    pyextend - python extend lib unpack (iterable, count, fill=None) 参数: iterable: 实现 __iter__的可迭代对象, 如 ...

  6. Xftp安装和使用的视频录制方法

    内容: 1.使用工具 2.操作步骤及方法 视频地址: http://v.youku.com/v_show/id_XMzEwNjg2MTg2NA==.html?spm=a2h3j.8428770.341 ...

  7. 软工1816 · Alpha冲刺(7/10)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 学会了POSTMAN的使用,对后端已经完成的接口进行了收发消息正确性的验证 推 ...

  8. web.config详解(转载)

    该文为转载 原文地址:http://www.cnblogs.com/gaoweipeng/archive/2009/05/17/1458762.html 花了点时间整理了一下ASP.NET Web.c ...

  9. lintcode-433-岛屿的个数

    433-岛屿的个数 给一个01矩阵,求不同的岛屿的个数. 0代表海,1代表岛,如果两个1相邻,那么这两个1属于同一个岛.我们只考虑上下左右为相邻. 样例 在矩阵: [ [1, 1, 0, 0, 0], ...

  10. TCP系列46—拥塞控制—9、SACK下的快速恢复与Limited transmit

    一.概述 1.SACK下的特殊处理过程 SACK下的拥塞控制处理是linux中拥塞控制的实现依据,再次强调一遍RFC6675的重要性,linux中拥塞控制主体框架的实现是与RFC6675一致的,所以如 ...