《你不知道的javascript》这本书读了有好几遍了,似乎每一次读都有新发现,有些内容并不是一下子可以弄懂的,每次读似乎都能明白一些概念。
再重读一下this关键字。这个概念非常灵活,也非常难掌握,所以我觉得经常读读没有坏处。期待javascript一桶江湖,这样学习的成本就低啦!
参考本书的第二部分的第一章,第二章。

this关键字是js中最最复杂的机制之一。他被自动定义到所有函数的作用域中。

在学习这个关键字的过程中似乎也走了很长时间的弯路。你要问我为什么走了很长时间的弯路,关键的地方还是没有对核心的概念彻底学习和领会,这一点和小学生学习新知识没有任何区别。要想掌握this这个关键字,需要紧扣关键概念,不要凭空想象这到底是怎么一回事。

关键概念:js中的函数在调用的时候,一定,一定,一定会绑定在一个对象上,在分析this关键字的时候,一定要知道函数在调用的时候这个对象到底是谁?。
切记:js中函数的调用和定义是没有任何关系的,函数所绑定的对象直到他被调用的时候才能知道。

this关键字的不确定定是把双刃剑,一是函数调用时的对象不确定性,是js中函数的使用具有很大灵活性,每个对象都可以借用其他函数来完成功能。二是这也造成了this学习的一些困扰。所以在学习的时候先要理解this关键字的优点,然后再去学习造成困扰的地方

首先看看第一段代码
page 75

  1. //注意只是定义了一个函数,并未调用,这时候函数是没有绑定任何对象
  2. function identify() {
  3. return this.name.toUpperCase();
  4. }
  5. //同上面的函数,但是这个函数内部有点复杂,如果下面的代码看不懂
  6. //可以只看上面的函数
  7. function speak() {
  8. var greeting = "Hello, I'm " + identify.call( this );
  9. console.log( greeting );
  10. }
  11. var me = { //定义了一个字面量对象
  12. name: "Kyle"
  13. };
  14. var you = {//定义了一个字面量对象
  15. name: "Reader"
  16. };
  17. //通过call方式把函数identify分别绑定到两个对象上
  18. //这时的this是指向me对象,和you对象
  19. identify.call( me ); // KYLE
  20. identify.call( you ); // READER
  21. //通过call方式把函数call分别绑定到两个对象上
  22. //这时的this是指向me对象,和you对象
  23. speak.call( me ); // Hello, I'm KYLE
  24. speak.call( you ); // Hello, I'm READER

在javascript中定义函数的时候,函数是不属于任何对象的。这一点非常的关键,非常的关键,非常的关键。这是理解this关键字的第一个障碍。

this关键字在js函数定义的时候的不确定性使得js函数使用有极大的灵活性,任何对象都可以使用他。

this到底是什么?

this的绑定和函数定义的位置没有任何关系,只取决于函数调用的方式.
javascript中当一个函数被调用的时候,会创建一个活动记录(有时也称上下文)。这个记录包括函数在哪里被调用,函数的调用方法,传入的参数。this就是记录中的一个属性。

这样在学习javascript关键字的首要问题是要解决怎么知道到函数的调用位置.

js对象绑定规则

每个js函数在调用的时候一定要找到一个对象,绑定以后才能使用。 这里是理解了js函数的定义和调用的区别以后需要掌握的一个规模最庞大的概念,在js中一共有四种绑定方式.就我个人来看,绑定规则并不难,难点还是在js的函数作用域的理解. 尤其是默认绑定.这个绑定方式有极大的迷惑性。

默认绑定

这个是函数的独立调用,也就是在一个函数直接调用的时候,似乎是没有绑定到对象上的,但是根据前面的介绍,js中函数调用时必须要绑定到一个对象上。
看下面代码 page 83

  1. function foo() { //这是函数的定义位置
  2. console.log( this.a );
  3. }
  4. var a = 2;//这个变量定义的含义是什么呢?仅仅是赋值给a吗?
  5. foo(); // 2 //这是函数的调用位置。为什么会打印出2呢?

很多函数都是这么调用的,照猫画虎也可以写出来,但是理解了具体的含义就不一样了。
foo这个函数定义在全局作用域中(window作用域中),巧合的是他的调用也是在全局作用域中,注意这仅仅是巧合,巧合。 那么foo()调用的时候为什么会打印出变量 a的值呢?尽管使用了var这个关键字,但是分析作用域可以知道,a这个变量实际是全局变量,说的再明白一点,a实际是window这个全局对象的一个属性,2是这个属性的属性值。
foo()调用的时候是一丝不挂的全裸状态,仅仅是函数本身,没有任何修饰符,这个时候他也没有任何函数包裹,处在全局作用域下面,所以foo()里面的this是指向全局对象的,当要打印this.a的时候,寻找foo()调用位置会找到全局作用域,找全局作用域的属性this.a的时候会打印出2这个属性值。

我们在使用setTimeout,setInterval函数的时候,实际这两个函数就是一丝不挂的,同样绑定在window对象上。

隐式绑定

函数在调用的时候被添加了修饰符。看下面这个代码
page 85

  1. function foo() { //定义在全局作用下的函数,仅仅是定义,不是调用位置
  2. console.log( this.a );
  3. }
  4. var obj = { //定义一个对象
  5. a: 2,
  6. foo: foo
  7. };
  8. obj.foo(); // 2 给foo()函数找了一个对象,this就指向这个对象了

这是最常见的方式了,如果不写前面的obj是不是就是上面的默认绑定了?

隐式丢失
经常在js代码的嵌套回调函数中看到在外层函数开始的一句

  1. var that=this; //这是什么含义

或许你已经会用了,但是理解了其中意义用起来会更加得心应手啊

看下面段代码.这段代码其实以前我也不太理解,问题还是没有彻底领悟js函数定义和调用之间是没有关系的这一点。
page 86

  1. function foo() { //定义了一个函数
  2. console.log( this.a );
  3. }
  4. var obj = { //定义了一个对象字面量
  5. a: 2,
  6. foo: foo //函数作为对对象的属性
  7. };
  8. var bar = obj.foo; //把obj对象的函数foo属性赋值给bar变量
  9. //这里就是理解这个问题的关键,如果你现在认为调用bar()的时候绑定的对象
  10. //是obj那就完全搞错了。这个时候仅仅是把函数foo赋值给了var变量,
  11. //并没有把对象也给bar变量,因为这里还不是foo()函数的调用位置,现在
  12. //foo函数还没有绑定对象,那么调用bar()的时候对象到底是谁?不知道。
  13. //调用的时候才知道。
  14. var a = "oops, global"; // 任然是全局对象的属性
  15. bar(); // "oops, global" 这里执行的是默认绑定,this就是去全局对象啦

下面这段代码就是使用var that=this的场景
在使用回调函数的时候要留心。js中函数是一等对象,可以作为另一个函数的参数传入函数。 问题就出在这里了,函数一旦作为实参代替形参的时候,实际也执行了和上面代码一样的赋值过程,实际只是传递了函数本身,原先的对象就没有了。

page 86

  1. function foo() { //定义一个函数
  2. console.log( this.a );
  3. }
  4. function doFoo(fn) { //fn是形参
  5. // 如果函数作为实参传入相当于代码 var fn=obj.foo
  6. //和上面一段代码是完全一样的,只是函数本身,并没有绑定任何对象
  7. fn(); // 在这里调用的时候,由于fn只代表foo()函数,被绑定到全局对象上了
  8. }
  9. var obj = {
  10. a: 2,
  11. foo: foo
  12. };
  13. var a = "oops, global"; // `a` also property on global object
  14. doFoo( obj.foo ); // "oops, global"不要被obj.foo迷惑了
  15. //没有实际执行函数的调用,此时obj.foo仅仅代表没有绑定任何对象的函数
  16. //这个代码块看着眼熟么?这就是javascript中回调函数的样子,当
  17. //一个函数作为参数传递进另一个函数的时候,这个参数函数就找不到自己绑定的对象是谁了,
  18. //所以就默认绑定到全局对象上了。但是我们既然在一个函数里调用另一个函数,肯定是要用这个函数操作当前的对象,那么既然找不到了,我们就手动给他指定一个对象吧。这就是为什么要使用
  19. //var that=this的原因。我觉得理解这个概念,js的功力至少会增加5%
  20. javascript你不知道的This的更多相关文章

      1. JavaScript 你不知道的事 -- 关于函数
      1. 接上篇Javascript 你不知道的事,直接条列了: 每个函数创建时默认带有一个prototype属性,其中包含一个constructor属性,和一个指向Object对象的隐藏属性__proto__ ...

      1. Javascript你不知道的那些事!(数字计算篇-变态篇)无意中聊天发现的一些奇怪的事情
      1. javascript:alert(0.1 + 0.2) 如果看到这样一道题你会怎么思考了!大家肯定第一反应0.3,但是考虑到我已经这样问了!那么幼稚的答案我会专门写篇文章吗 然后人就开始折磨自己了会不 ...

      1. Javascript 你不知道的事,好吧,是我不知道的事
      1. NaN表示一个不能产生正常结果的运算结果.它不等于任何值,包括它自己.可以用isNaN(number)来检测. Java中的字符串一样,JS中的字符串是不可变的.也就是说一旦字符串被创建,就无法改变 ...

      1. Javascript 你不知道的事
      1. NaN表示一个不能产生正常结果的运算结果.它不等于任何值,包括它自己.可以用isNaN(number)来检测. Java中的字符串一样,JS中的字符串是不可变的.也就是说一旦字符串被创建,就无法改变 ...

      1. 《你不知道的JavaScript》整理(二)——this
      1. 最近在读一本进阶的JavaScript的书<你不知道的JavaScript(上卷)>,这次研究了一下“this”. 当一个函数被调用时,会创建一个活动记录(执行上下文). 这个记录会包含函 ...

      1. 《你不知道的JavaScript》整理(一)——作用域、提升与闭包
      1. 最近在读一本进阶的JavaScript的书<你不知道的JavaScript(上卷)>,里面分析了很多基础性的概念. 可以更全面深入的理解JavaScript深层面的知识点. 一.函数作用域 ...

      1. 你不知道的Javascript(上卷)读书笔记之一 ---- 作用域
      1. 你不知道的Javascript(上卷)这本书在我看来是一本还不错的书籍,这本书用比较简洁的语言来描述Js的那些"坑",在这里写一些博客记录一下笔记以便消化吸收. 1 编译原理 在此 ...

      1. 你不知道的JavaScript上卷笔记
      1. 你不知道的JavaScript上卷笔记 前言 You don't know JavaScript是github上一个系列文章   初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目 ...

      1. 【读书笔记】-- 你不知道的JavaScript
      1. <你不知道的JavaScript>是一个不错的JavaScript系列书,书名可能有些标题党的意思,但实符其名,很多地方会让你有耳目一新的感觉. 1.typeof null === &qu ...

    1. 随机推荐

        1. BZOJ4939 Ynoi2016掉进兔子洞(莫队+bitset)
        1. 容易发现要求三个区间各数出现次数的最小值.考虑bitset,不去重离散化后and一发就可以了.于是莫队求出每个区间的bitset.注意空间开不下,做多次即可.输出的东西错了都能调一年服了我了. #in ...

        1. 洛谷 P3258 [JLOI2014]松鼠的新家
        1. 树剖,裸题,鉴定完毕. 我是题面 读完题,恩,树剖,裸题,没劲. 处理很简单,既然每到一个房间吃一块糖,那么就在每条路径上的每个房间放一颗糖,但是每条路径的终点也就是下一条路径的起点,在这里只能加一次 ...

        1. x64 win64编译环境下ADO链接Access数据库的问题解决
        1. 原文链接地址:https://blog.csdn.net/HW140701/article/details/71077579 Win32编译环境下,用ADO数据库连接Access数据库一般都不会报错, ...

        1. MSSQL代理工作服务器远程命令执行
        1. 概述 如果MSSQL数据库中开启了MSSQL Server Agent Job服务的话,攻击者将可以利用MSSQL Server中自带的功能来获取一个shell. SQL Server Agent S ...

        1. android ndk 编译的时候指令集的选取
        1. android ndk在编译的时候默认生成的是thumb指令(拇指)不是arm(手臂)指令,但是有时候在看反汇编的时候,不太熟悉thumb指令或者说thumb指令看起来更费劲,需要生成arm指令,这个 ...

        1. hdu6166 Senior Pan
        1. Senior Pan Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Tot ...

        1. Socket初识2
        1. 一.Socket一些概念 sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) 1.1 参数1:Socket Families(地址簇) / ...

        1. ASP.NET MVC4+EasyUI+EntityFrameWork5权限管理系统——数据库的设计(一)
        1. 快一年没写博客了,这段时间感觉好迷茫,写点博客,记录一下自己的成长过程,希望对大家也有帮助 先上图 一个用户可以有多个角色,一个用户可以属于多个部门,这些都可以控制到权限,有时特殊要求,同样的部门和角 ...

        1. 2.redis设计与实现--链表
        1. 1.链表节点: 2.链表: 3.总结

        1. 分治法:三维偏序问题之CDQ分治
        1. 我怀疑那个k是用来定界限用的 #include <cstdio> #include <cstring> #include <algorithm> using nam ...