记得刚开始,我理解 this 的时候 也是云里雾里的,哈哈,希望通过这篇文章,对你有帮助吧。

关于 this 最多的说法,就是:谁调用它,this就指向谁。这话呢,不能说它错了,只能说它讲的不严谨,为什么呢?我们先来了解下 this 的几种绑定规则。

一、默认绑定

默认绑定 发生在全局环境 。

全局环境中,this 默认绑定到 window。(严格模式下一样)

console.log(this === window);
//true"use strict";    //使用严格模式执行代码
var a = 666;
console.log(this.a)//666

二、隐式绑定

隐式绑定 发生在 方法调用(执行)。

什么是方法呢?通常把 对象的属性值 是函数的,称为方法。

var obj = {fun: function(){}
}//这里obj 对象里 的fun 属性值是个函数, 就把 这个fun 属性称为方法了。

通常,方法调用时,this 隐式绑定到其 所属的对象 上。

var a = "window";var obj = {a: "obj",fun: function(){console.log(this.a);}
}obj.fun();//"obj"

来个难一点的:

var obj1 = {a: "obj1",obj2: {a: "obj2",fun: function(){console.log(this.a);}}
}obj1.obj2.fun();//"obj2"

这里的答案 跟你想的一样吗? 出现这个答案的关键 就是于,fun 函数 在作为对象方法执行时, this 绑定的是它的 所属对象,也就是 obj2 。 而非外层 的 obj1

三、隐式绑定丢失

在判断是否是隐式绑定的时候,最容易出问题的地方就是发生在 隐式绑定丢失。

隐式丢失是指被隐式绑定的函数丢失绑定对象,从而绑定到window。这种情况容易出错却又常见。(严格模式下,绑定到undefined)

隐式绑定丢失 一般 发生在 函数独立调用时。

啥是独立调用呢?就是一个简单的函数执行. 函数名的前面没有任何引导内容。

function ff(){};ff();   //独立调用

当函数独立调用(执行)时,this 就会隐式绑定丢失,而绑定到 window 对象上。(非严格模式下)

function fun(){console.log(this === window);
}
fun();
//true

那么严格模式下呢?是指向 undefined 的。

function fun(){"use strict";    //使用严格模式执行代码console.log(this);
}
fun();//undefined

考考你:

var a = "window";var obj = {a: "obj",fun1: function(){console.log(this.a);}
}var fun2 = obj.fun;fun2();
//"window"

判断是否隐式绑定丢失的关键就在于, 判断函数 是否是哪种调用。

上面的例子,关键点就在 最后两行代码。
先看其中的第一行:

var fun2 = obj.fun;

这里把 obj 的fun 方法 赋值给了 一个变量 fun2,这里的 fun 并没有作为对象的方法来执行,因为,fun 方法这里没有执行。

其后:

fun2();

再执行 fun2,它保存着 fun1 方法,这时候执行 fun2(等于fun1) ,但是,它是独立调用。因为,没有作为对象的方法来调用。所以 this 就被指向 window了。

那么怎么解决隐式丢失问题呢?

var a = "window";var obj = {a: "obj",fun: function(){return function(){console.log(this.a);}}
}obj.fun()();//"window"//这里我们想要的是 obj里 a 的值,可是,隐式绑定丢失导致获取到了 window 里 a 的值。

可以基础好的已经知道答案了:

var a = "window";var obj = {a: "obj",fun: function(){var that = this;return function(){console.log(that.a);}}
}obj.fun()();//"obj"

因为 fun 是作为方法调用的,所以 this 绑定到 obj 对象上,因此,我们就可以先用一个变量 that 来保存 this,然后 在内部的 匿名函数中 使用 that 就可以了。它保存着 上面 this 的绑定对象。

忽然灵机一动,想出个题目,看人家都玩出题,我也试试,哈哈:

var a = "window";function fun(){var a = "fun";return (function(){return this.a;})()
}fun()//“你猜”

这道题中 有立即执行函数、this问题,哈哈,乍一看挺恶心,其实看完上面的,应该可以看出来的。

四、显示绑定

通过call()、apply()、bind()方法把 this 绑定到对象上,叫做显式绑定。对于被调用的函数来说,叫做间接调用

var a = "window"var obj = {a:"obj",
}function fun(){console.log(this.a);
}fun.call(obj);
//"obj";

这里使用了 call 方法,把fun 中的 this 绑定到 obj 对象上。

javascript内置的一些函数,具有显式绑定的功能,如数组的5个迭代方法:map()、forEach()、filter()、some()、every(),以及创建对象的 Object.create() 函数(后面原型链中会细说),都可以手动绑定this。

大家可以去看下API文档,数组的这几个函数的最后一个参数,就是指定函数内 this 的绑定,如果不指定,则是window,严格模式下是undefined

var a = [1,2,3];a.forEach(function(){console.log(this)
},a);//绑定 this  为 a 这个数组//(3) [1, 2, 3]
//(3) [1, 2, 3]
//(3) [1, 2, 3]

五、new 绑定

如果 使用 new 来创建对象,因为 后面跟着的是构造函数,所以称它为构造器调用。对于this绑定来说,称为new绑定。

想知道 构造器调用 中 this 的绑定,就要知道 new 到底做了啥了。

先来个 new 的实现。看不懂不要紧,在后面原型链那篇,还会说的。

function New(proto){  //proto 为传进来的构造函数var obj = {};obj.__proto__ = proto.prototype;proto.apply(obj, Array.prototype.slice.call(argument,1));//你这要看懂这步就行。这里把构造函数里的 this  绑定到了 新的obj 对象上,最后 返回了该新对象,作为实例对象。return obj;
}

所以在使用 new 来创建实例对象时,new 内部把 构造函数的 this 绑定到 返回的新对象 上了。

function Person(name){this.name = name;
}
var c = new Person("zdx");
c.name;

总结: this的四种绑定规则:隐式绑定、隐式绑定丢失、显式绑定和new绑定,分别对应函数的四种调用方式:方法调用、独立调用、间接调用和构造器调用。

附录:

1、关于this绑定 的优先级问题。

简单提一下吧:

new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定

2、ES6 中,箭头函数的 this 绑定。

箭头函数内的 this 绑定的 是所属的环境(函数或者对象), 它是固定不变的。

先看下上面的这个例子

var a = "window";var obj = {a: "obj",fun: function(){return function(){console.log(this.a);}}
}obj.fun()();//"window"

上面我们使用 一个变量来保存 this 的绑定,下面我们来用 箭头函数解决问题

var a = "window";var obj = {a: "obj",fun: function(){return () => {console.log(this.a);}}
}obj.fun()();//"obj"

实际上,箭头函数内部是没有this 的,所以,它不能使用 new 构造器调用,call显示绑定。所以它内部就是使用了一个变量来保存 箭头函数 所属环境的(函数或者对象) this

就相当于:

var a = "window";var obj = {a: "obj",fun: function(){that = this;return function(){console.log(that.a);}}
}obj.fun()();//"obj"

考考你:

var a = "window";var obj = {a: "obj",fun1: function(){return () => {console.log(this.a);}}
}var fun2  = obj.fun1;fun2()();

转载于:https://www.cnblogs.com/zhoudaxiaa/p/9705707.html

进击的 JavaScript(六) 之 this相关推荐

  1. 进击的 JavaScript 之(七) 原型链

    原文链接:周大侠啊 进击的 JavaScript (七) 之 原型链 算是记录一下自己的学习心得吧,哈哈 首先说一下,函数创建的相关知识 在JavaScript中,我们创建一个函数A(就是声明一个函数 ...

  2. JavaScript(六)

    JavaScript(六) 一.正则表达式: 1.每个字符集只能匹配一个字符 2.备选字符集中至少有一个匹配上 ex:[a-zA-Z0-9]所有的应为字母和数字 [\u4e00-\u9fa5]一个汉字 ...

  3. 进击的JavaScript(对象,继承,单例模式)

    1.   JavaScript的面向对象 怎么理解js的面向对象编程 面向对象:对外统一提供调用接口的编程思想. 对象: 依靠构造器(constructor)利用原型(prototype)构造出来. ...

  4. 进击的 JavaScript(四) 之 闭包

    上一节说了执行上下文,这节咱们就乘胜追击来搞搞闭包!头疼的东西让你不再头疼! 一.函数也是引用类型的. function f(){ console.log("not change" ...

  5. 幽情阁--Java8系列之Nashorn JavaScript(六)

    本章小宋讲一下JavaScript的引擎Nashorn 目录 Nashorn jjs jjs 交互式编程 jjs传递参数 Java 中调用 JavaScript JavaScript 中调用 Java ...

  6. Javascript(六十三)网络协议

    网络分层的概念 OSI 7层的网络分层 通用 5层网络分层 网络传输协议:网络数据在互联网进行传输,遵从的传输规则 传输层:TCP/UDP port端口号(确定来自哪个软件) 网络层:IP协议 确定传 ...

  7. ApacheCN JavaScript 译文集(二) 20211123 更新

    使用 Meteor 构建单页 Web 应用 零.前言 一.制作 Meteor 应用 二.构建 HTML 模板 三.存储数据和处理集合 四.控制数据流 五.使我们的应用与路由通用 六.保持会话状态 七. ...

  8. ApacheCN JavaScript 译文集 20211122 更新

    JavaScript 编程精解 中文第三版 零.前言 一.值,类型和运算符 二.程序结构 三.函数 四.数据结构:对象和数组 五.高阶函数 六.对象的秘密 七.项目:机器人 八.Bug 和错误 九.正 ...

  9. 基于HTML+CSS+JavaScript “小味鲜“餐厅网页设计

    基于HTML+CSS+JavaScript "小味鲜"餐厅网页设计 每博一文案 师父说"生活中的负能大多来于圈子里的抱怨",有时候,你不想做别人情绪的垃圾桶. ...

最新文章

  1. 获得TADIR-OBJECT全部的entry list
  2. 管理多个Java安装
  3. 从中师到博士,我用了22年...
  4. ECCV 2020 | 微软亚洲研究院精选论文摘录
  5. python逢7跳过_python实现逢七拍腿小游戏的思路详解
  6. WindowsServer2012 DFS配置出错原因
  7. 第一章 微服务网关 - 入门
  8. ggplot2分面柱状图柱子比例一致_R语言柱状图
  9. 工程学导论1---3章习题与思考题
  10. 《嵌入式C编程:PIC单片机和C编程技术与应用》一导读
  11. [python爬虫] Selenium爬取新浪微博内容及用户信息
  12. 计算机学情分析案例,小学信息技术课学情分析
  13. windows_帮助文档【.CHM电子书】打开显示空白解决办法
  14. 边境的悍匪—机器学习实战:第十四章 使用卷积神经网络的深度计算机视觉
  15. 【RocketMQ】从零搭建一套RocketMQ监控(rocketmq-exporter + Prometheus + Grafana)
  16. 平板电脑win10 android比较好,华为MateBook名不副实!Win10平板电脑最合适
  17. Rime输入法小狼毫皮肤配色
  18. 超简单的页眉页脚设置(摘要、目录页眉不同、页脚页码连续)
  19. 2<<3是什么意思?
  20. 建一个手机网站到底需要多少钱

热门文章

  1. Using Markov Chains for Android Malware Detection
  2. 深入理解Android的startservice和bindservice
  3. 工作单元php,php – 无法从工作单元测试用例构建最简单的套件
  4. linux进程卡住_鸿蒙系统,Linux? Android?
  5. spring-mybatis.xml 访问html5,Spring mvc无xml配置及利用JdbcTemplate访问数据库
  6. mac 当前文件夹打开终端_Mac上的这些实用你技巧,你知道几个?
  7. 窗口位置按钮取消_梦幻西游:五开玩家都是怎样摆放窗口的
  8. 文本分类入门(四)训练Part 1
  9. 数学之美系列之一:统计语言模型 (Statistical Language Models)
  10. JZOJ__Day 1:【普及模拟】PLES