第一章  关于this

1、this 既不指向函数自身也不指向函数的词法作用域

2、this 实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用(调用位置)。

第二章 this全面解析

调用栈与调用位置

  1. function baz() {
  2. // 当前调用栈是:baz
  3. // 因此,当前调用位置是全局作用域
  4.   console.log( "baz" );
  5.   bar(); // <-- bar 的调用位置
  6. }
  7. function bar() {
  8. // 当前调用栈是 baz -> bar
  9. // 因此,当前调用位置在 baz 中
  10.   console.log( "bar" );
  11.   foo(); // <-- foo 的调用位置
  12. }
  13. function foo() {
  14. // 当前调用栈是 baz -> bar -> foo
  15. // 因此,当前调用位置在 bar 中
  16.   console.log( "foo" );
  17. }
  18. baz(); // <-- baz 的调用位置

绑定规则【四个】:

1、默认绑定 

最常用的函数调用类型:独立函数调用。但是在严格模式下是不可行的。

this 的绑定规则完全取决于调用位置,但是只有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo()的调用位置无关

例子

  1. function foo() {
  2.   console.log( this.a );
  3. }
  4. var a = 2;
  5. foo(); //

如果使用严格模式(strict mode),那么全局对象将无法使用默认绑定,因此 this 会绑定 到 undefined:

  1. function foo() {
  2. "use strict";
  3. console.log( this.a );
  4. }
  5. var a = 2;
  6. foo(); // TypeError: this is undefined

虽然 this 的绑定规则完全取决于调用位置,但是只 有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo() 的调用位置无关【但是通常不会混用】

  1. function foo() {
    console.log( this.a );
    }
  2.  
  3. var a = ;
  4.  
  5. (function(){
    "use strict";
  6. foo(); // 2
    })();

2、隐式绑定

例子:因为当 foo() 被调用时,它的落脚点确实指向 obj 对象。当函数引 用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。因为调 用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的

  1. function foo() {
  2.   console.log( this.a );
  3. }
  4.  
  5. var obj = {
  6.   a: 2,
  7.   foo: foo
  8. };
  9.  
  10. obj.foo(); //

最近原则 对象属性引用链中只有最顶层或者说最后一层会影响调用位置

  1. function foo() {
  2.   console.log( this.a );
  3. }
  4.  
  5. var obj2 = {
  6.   a: 42,
  7.   foo: foo
  8. };
  9.  
  10. var obj1 = {
  11.   a: 2,
  12.   obj2: obj2
  13. };
  14.  
  15. obj1.obj2.foo(); //

3、显示绑定(不想在对象内部包含函数引用。而是在某个对象上强制调用函数)

解决方法:使用函数的call()和apply()方法,这两个方法的第一个参数是一个对象,他们会把这个对象绑定到this,接着调用函数时指定这个this。

(1)call()方法  通过 foo.call(..),我们可以在调用 foo 时强制把它的 this 绑定到 obj 上。

  1. function foo() {
  2. console.log( this.a );
  3. }
  4.  
  5. var obj = {
  6. a:2
  7. };
  8.  
  9. foo.call( obj ); // 2

硬绑定 可以解决丢失绑定问题

(2)硬绑定的典型应用场景就是创建一个包裹函数,传入所有的参数并返回收到的所有值

例如

  1. function foo(something) {
  2. console.log( this.a, something );
  3. return this.a + something;
  4. }
  5.  
  6. var obj = {
  7. a:2
  8. };
  9.  
  10. var bar = function() {
  11. return foo.apply( obj, arguments );
  12. };
  13.  
  14. var b = bar( 3 ); // 2 3
  15. console.log( b ); //

(3)另外一个使用方法是创建一个i可以重复使用的辅助函数

  1. function foo(something) {
  2. console.log( this.a, something );
  3. return this.a + something;
  4. }
  5.  
  6. // 简单的辅助绑定函数
  7. function bind(fn, obj) {
  8. return function() {
  9. return fn.apply( obj, arguments );
  10. };
  11. }
  12.  
  13. var obj = {
  14. a:2
  15. };
  16.  
  17. var bar = bind( foo, obj );
  18.  
  19. var b = bar( 3 ); // 2 3
  20. console.log( b ); //

噔噔噔噔.....由于硬绑定是一个非常常用的模式,所以在ES5中提供了内置的方法 Function.prototype. bind,使用方法如下:

bind(..) 会返回一个硬编码的新函数,它会把参数设置为 this 的上下文并调用原始函数。

  1. function foo(something) {
  2. console.log( this.a, something );
  3. return this.a + something;
  4. }
  5. var obj = {
  6. a:2
  7. };
  8.  
  9. var bar = foo.bind( obj );
  10. var b = bar( 3 ); // 2 3
  11. console.log( b ); //

4、new绑定

JavaScript的“构造函数”只是一些 使用 new 操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。实际上, 它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已

第一章  关于this

1、this 既不指向函数自身也不指向函数的词法作用域

2、this 实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用(调用位置)。

第二章 this全面解析

调用栈与调用位置

  1. function baz() {
  2. // 当前调用栈是:baz
  3. // 因此,当前调用位置是全局作用域
  4.   console.log( "baz" );
  5.   bar(); // <-- bar 的调用位置
  6. }
  7. function bar() {
  8. // 当前调用栈是 baz -> bar
  9. // 因此,当前调用位置在 baz 中
  10.   console.log( "bar" );
  11.   foo(); // <-- foo 的调用位置
  12. }
  13. function foo() {
  14. // 当前调用栈是 baz -> bar -> foo
  15. // 因此,当前调用位置在 bar 中
  16.   console.log( "foo" );
  17. }
  18. baz(); // <-- baz 的调用位置

绑定规则【四个 默认绑定 隐式绑定 显式绑定 new绑定】:

1、默认绑定 

最常用的函数调用类型:独立函数调用。但是在严格模式下是不可行的。

this 的绑定规则完全取决于调用位置,但是只有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo()的调用位置无关

例子

  1. function foo() {
  2.   console.log( this.a );
  3. }
  4. var a = 2;
  5. foo(); // 2

如果使用严格模式(strict mode),那么全局对象将无法使用默认绑定,因此 this 会绑定 到 undefined:

  1. function foo() {
  2. "use strict";
  3. console.log( this.a );
  4. }
  5. var a = 2;
  6. foo(); // TypeError: this is undefined

虽然 this 的绑定规则完全取决于调用位置,但是只 有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo() 的调用位置无关【但是通常不会混用】

  1. function foo() {
    console.log( this.a );
    }
  2.  
  3. var a = 2;
  4.  
  5. (function(){
    "use strict";
  6. foo(); // 2
    })();

2、隐式绑定

例子:因为当 foo() 被调用时,它的落脚点确实指向 obj 对象。当函数引 用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。因为调 用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的

  1. 1 function foo() {
  2. 2   console.log( this.a );
  3. 3 }
  4. 4
  5. 5 var obj = {
  6. 6   a: 2,
  7. 7   foo: foo
  8. 8 };
  9. 9
  10. 10 obj.foo(); // 2

最近原则 对象属性引用链中只有最顶层或者说最后一层会影响调用位置

  1. 1 function foo() {
  2. 2   console.log( this.a );
  3. 3 }
  4. 4
  5. 5 var obj2 = {
  6. 6   a: 42,
  7. 7   foo: foo
  8. 8 };
  9. 9
  10. 10 var obj1 = {
  11. 11   a: 2,
  12. 12   obj2: obj2
  13. 13 };
  14. 14
  15. 15 obj1.obj2.foo(); // 42

3、显式绑定(不想在对象内部包含函数引用。而是在某个对象上强制调用函数)

解决方法:使用函数的call()和apply()方法,这两个方法的第一个参数是一个对象,他们会把这个对象绑定到this,接着调用函数时指定这个this。

(1)call()方法  通过 foo.call(..),我们可以在调用 foo 时强制把它的 this 绑定到 obj 上。

  1. 1 function foo() {
  2. 2 console.log( this.a );
  3. 3 }
  4. 4
  5. 5 var obj = {
  6. 6 a:2
  7. 7 };
  8. 8
  9. 9 foo.call( obj ); // 2

硬绑定 可以解决丢失绑定问题

(2)硬绑定的典型应用场景就是创建一个包裹函数,传入所有的参数并返回收到的所有值

例如

  1. 1 function foo(something) {
  2. 2 console.log( this.a, something );
  3. 3 return this.a + something;
  4. 4 }
  5. 5
  6. 6 var obj = {
  7. 7 a:2
  8. 8 };
  9. 9
  10. 10 var bar = function() {
  11. 11 return foo.apply( obj, arguments );
  12. 12 };
  13. 13
  14. 14 var b = bar( 3 ); // 2 3
  15. 15 console.log( b ); // 5

(3)另外一个使用方法是创建一个i可以重复使用的辅助函数

  1. function foo(something) {
  2. console.log( this.a, something );
  3. return this.a + something;
  4. }
  5.  
  6. // 简单的辅助绑定函数
  7. function bind(fn, obj) {
  8. return function() {
  9. return fn.apply( obj, arguments );
  10. };
  11. }
  12.  
  13. var obj = {
  14. a:2
  15. };
  16.  
  17. var bar = bind( foo, obj );
  18.  
  19. var b = bar( 3 ); // 2 3
  20. console.log( b ); // 5

噔噔噔噔.....由于硬绑定是一个非常常用的模式,所以在ES5中提供了内置的方法 Function.prototype. bind,使用方法如下:

bind(..) 会返回一个硬编码的新函数,它会把参数设置为 this 的上下文并调用原始函数。

  1. 1 function foo(something) {
  2. 2 console.log( this.a, something );
  3. 3 return this.a + something;
  4. 4 }
  5. 5 var obj = {
  6. 6 a:2
  7. 7 };
  8. 8
  9. 9 var bar = foo.bind( obj );
  10. 10 var b = bar( 3 ); // 2 3
  11. 11 console.log( b ); // 5

4、new绑定

JavaScript的“构造函数”只是一些 使用 new 操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。实际上, 它们甚至都不能说是一种特殊的函数类型,它们只是被 new 操作符调用的普通函数而已。

包括内置对象函数(比如 Number(..) ,详情请查看第 3 章)在内的所有函数都可
以用 new 来调用,这种函数调用被称为构造函数调用。这里有一个重要但是非常细微的区
别:实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。

使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

1. 创建(或者说构造)一个全新的对象。
2. 这个新对象会被执行 [[ 原型 ]] 连接。
3. 这个新对象会绑定到函数调用的 this 。
4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。

例如

  1. 1 function foo(a) {
  2. 2 this.a = a;
  3. 3 }
  4. 4 var bar = new foo(2);
  5. 5 console.log( bar.a ); // 2

使用 new 来调用 foo(..) 时,我们会构造一个新对象并把它绑定到 foo(..) 调用中的 this上。 new 是最后一种可以影响函数调用时 this 绑定行为的方法,我们称之为 new 绑定。

5、优先级

这四个绑定的优先级   new绑定 > 显式绑定 > 隐式绑定 > 默认绑定

判断 this
现在我们可以根据优先级来判断函数在某个调用位置应用的是哪条规则。可以按照下面的
顺序来进行判断:

1. 由 new 调用?绑定到新创建的对象。
2. 由 call 或者 apply (或者 bind )调用?绑定到指定的对象。
3. 由上下文对象调用?绑定到那个上下文对象。
4. 默认:在严格模式下绑定到 undefined ,否则绑定到全局对象。

6、绑定例外

更安全的this

在 JavaScript 中创建一个空对象最简单的方法都是 Object.create(null)(详细介绍请看第 5 章)。 Object.create(null) 和 {} 很像,但是并不会创建 Object.prototype 这个委托,所以它比 {} “更空”:

  1. 1 function foo(a,b) {
  2. 2 console.log( "a:" + a + ", b:" + b );
  3. 3 }
  4. 4 // 我们的 DMZ 空对象
  5. 5 var ø = Object.create( null );
  6. 6 // 把数组展开成参数
  7. 7 foo.apply( ø, [2, 3] ); // a:2, b:3
  8. 8 // 使用 bind(..) 进行柯里化
  9. 9 var bar = foo.bind( ø, 2 );
  10. 10 bar( 3 ); // a:2, b:3

间接引用 间接引用最容易在赋值时发生:

  1. 1 function foo() {
  2. 2 console.log( this.a );
  3. 3 }
  4. 4 var a = 2;
  5. 5 var o = { a: 3, foo: foo };
  6. 6 var p = { a: 4 };
  7. 7 o.foo(); // 3
  8. 8 (p.foo = o.foo)(); // 2

赋值表达式 p.foo = o.foo 的返回值是目标函数的引用,因此调用位置是 foo() 而不是p.foo() 或者 o.foo() 。根据我们之前说过的,这里会应用默认绑定。

注意:对于默认绑定来说,决定 this 绑定对象的并不是调用位置是否处于严格模式,而是函数体是否处于严格模式。如果函数体处于严格模式, this 会被绑定到 undefined ,否则this 会被绑定到全局对象。

软绑定

给默认绑定指定一个全局对象和 undefined 以外的值,那就可以实现和硬绑定相同的效果,同时保留隐式绑定或者显式绑定修改 this 的能力。 softBind(..)

7、this词法

ES6 中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this ,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样。

例如:foo() 内部创建的箭头函数会捕获调用时 foo() 的 this 。由于 foo() 的 this 绑定到 obj1 ,bar (引用箭头函数)的 this 也会绑定到 obj1 ,箭头函数的绑定无法被修改。( new 也不行!)

  1. 1 function foo() {
  2. 2 // 返回一个箭头函数
  3. 3 return (a) => {
  4. 4 //this 继承自 foo()
  5. 5 console.log( this.a );
  6. 6 };
  7. 7 }
  8. 8 var obj1 = {
  9. 9 a:2
  10. 10 };
  11. 11 var obj2 = {
  12. 12 a:3
  13. 13 };
  14. 14 var bar = foo.call( obj1 );
  15. 15 bar.call( obj2 ); // 2, 不是 3

其实,箭头函数最常用于回调函数中,例如事件处理器或者定时器

  1. function foo() {
  2. setTimeout(() => {
  3. // 这里的 this 在此法上继承自 foo()
  4. console.log( this.a );
  5. },100);
  6. }
  7. var obj = {
  8. a:2
  9. };
  10. foo.call( obj ); // 2

而且箭头函数可以像bin()一样确保函数的this被绑定到指定的对象,其重要性还体现在它用更常见的词法作用域取代了传统的 this 机制.

你不知道的JavaScript(上)this和对象原型(一)的更多相关文章

  1. 读书笔记-你不知道的JavaScript(上)

    本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...

  2. 《你不知道的javascript(上)》笔记

    作用域是什么 编译原理 分词/词法分析 这个过程会将由字符组成的字符串分解成(对编程语言来说)有意义的代码块,这些代码块被称为词法单元 解析/语法分析 词法单元流(数组)转换成一个由元素逐级嵌套所组成 ...

  3. 你不知道的JS之 this 和对象原型(一)this 是什么

     原文:你不知道的js系列 JavaScript 的 this 机制并没有那么复杂 为什么会有 this? 在如何使用 this 之前,我们要搞清楚一个问题,为什么要使用 this. 下面的代码尝试去 ...

  4. 《你不知道的Javascript》感悟篇—对象属性遍历的那些事

    划重点 本篇笔者将重点介绍JavaScript中 getOwnPropertyNames .Object.keys.for ... in 的使用及他们之间的异同点. getOwnPropertyNam ...

  5. JavaScript 之 原型对象、对象原型 —— { }

    JavaScript -- 构造函数 // 构造函数 function Player(name, age) { this.name = name; this.age = age; } JavaScri ...

  6. JavaScript中的对象与原型—你不知道的JavaScript上卷读书笔记(四)

    一.对象 对象可以通过两种形式定义:声明(文字)形式和构造形式.即: var myObj = { key: value // ... }; 或: var myObj = new Object(); m ...

  7. 《你必须知道的javascript(上)》- 2.this与对象原型

    1 关于this 1.1 为什么使用this 随着你的使用模式越来越复杂,显式传递上下文对象会让代码变得越来越混乱,使用this则不会这样.当我们介绍对象和原型时,你就会明白函数可以自动引用合适的上下 ...

  8. 《你不知道的JavaScript》整理(三)——对象

    一.语法 两种形式定义:文字形式和构造形式. //文字形式 var myObj = { key: value }; //构造形式 var myObj = new Object(); myObj.key ...

  9. 关于Javascript中通过实例对象修改原型对象属性值的问题

    Javascript中的数据值有两大类:基本类型的数据值和引用类型的数据值. 基本类型的数据值有5种:null.undefined.number.boolean和string. 引用类型的数据值往大的 ...

  10. Javascript函数、构造函数、原型、类和对象

    函数 函数是JavaScript中特殊的对象,对函数执行typeof运算会返回字符串"function",因为函数也是对象,他们可以拥有属性和方法. 静态方法 函数在JS中定义了类 ...

随机推荐

  1. 给公司写的composer包开发的规范

    版本格式 主版本号.次版本号.修订号 版本号递增规则 主版本号:当你做了不兼容的 API 修改 次版本号:当你做了向下兼容的功能性新增 修订号:当你做了向下兼容的问题修正 先行版本号及版本编译元数据可 ...

  2. 2019-10-28:渗透测试学习,sqlmap的使用,笔记

    sqlmap工具的使用sql注入工具,明小子,啊D,萝卜头,穿山甲,sqlmap等开源自动化注入利用工具,支持的数据库有12种,在/plugins中可以看到支持的数据库种类,在所有注入利用工具中是最好 ...

  3. JavaScript笔记六

    1.对象(Object) - 对象是JS中的引用数据类型 - 对象是一种复合数据类型,在对象中可以保存多个不同数据类型的属性 - 使用typeof检查一个对象时,会返回object - 创建对象 - ...

  4. 在centos7上进行hadoop-3.1.2的伪分布搭建

    第一步:配置网络(静态IP) vi /etc/sysconfig/network-scripts/ifcfg-ens33(网卡名称可能不同) 1. 修改: 将该配置文件中的ONBOOT=no修改为ye ...

  5. 痞子衡嵌入式:恩智浦i.MX RTxxx系列MCU启动那些事(1)- Boot简介

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RTxxx系列MCU的BootROM功能简介. 截止目前为止i.MX RTxxx系列已公布的芯片仅有一款i.MXRT60 ...

  6. mysql插入的时间莫名的加一秒

    1.问题描述 我获取当天最大的时间: public static Date getEndOfDay(Date date) { LocalDateTime localDateTime = LocalDa ...

  7. java this,super简单理解

    *****this****** 表示对当前对象的引用. 作用:1.区分实例变量和局部变量(this.name----->实例变量name) 2.将当前对象当做参数传递给其它对象和方法.利用thi ...

  8. MySQL事务和隔离级别

    Mysql事务 避免事务,会占用内存 事务是啥? 简而言之:事务 - 就是保护多条执行的sql语句,要么全部成功,要么全部失败 比如:转账就是一个事务:从一个用户将资金转出,再将资金转入到另一个用户, ...

  9. GItBook命令使用(持续更新)

    GitBook基本命令 gitbook init //初始化目录文件 gitbook help //列出gitbook所有的命令 gitbook --help //输出gitbook-cli的帮助信息 ...

  10. 关于c++函数里面return的用法,关于调用的讲解

    与下面的图片对比一下 可以看见在int b = test();d的时候cout<<"hello";就被调用了: cout<<b;只是返回return a的值 ...