博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于this的全面解析(上)
阅读量:6426 次
发布时间:2019-06-23

本文共 3187 字,大约阅读时间需要 10 分钟。

this的调用位置

调用位置就是函数在代码中被调用的位置(而不是声明的位置),寻找调用位置就是寻找“函数被调用的位置”,最重要的是分析调用栈(就是为了到达当前执行位置所调用的所有函数)。

function baz() {        //当前调用栈是baz        //当前调用位置是全局位置        console.log('baz');        bar(); //<--bar的调用位置    }    function bar() {        //当前的调用栈是baz->bar        //因此当前的调用位置在baz中        console.log('bar');        foo(); //<--foo的调用位置    }    function foo() {        //当前的调用栈是baz->bar->foo        //因此当前的调用位置在bar中        console.log('foo');    }    baz(); //<-baz的调用位置

把调用栈想象成一个函数调用链,如上图代码中的样式,但是这种方法非常麻烦并且容易出错。另一个查看调用栈的方法是使用浏览器的调试工具。

绑定规则

首先需要找到调用位置,然后判断寻求下列四条规则中的哪一条。

1 默认绑定

首先介绍最常用的函数调用类型:独立函数调用。可以把这条规则看作是无法应用其他规则时的默认规则。

function foo() {        console.log(this.a); //<-this指向全局作用域    }    var a = 2;    foo(); //<-foo调用位置

在代码中,foo()是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。

function foz() {        "use strict";        console.log(this.a); //<--严格模式下不能将全局对象用于绑定    }    foz(); //TypeError

2 隐藏绑定

另一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包含,这种说法有时候会有误导。

function foa() {        console.log(this.a);    }    var foaObj = {        a: "Hello",        foa: foa //<--foa函数调用位置    }    foaObj.foa();

foa函数在严格意义上来说不属于foaObj对象。然而,调用位置会使用foaObj上下文来引用函数,因此可以判断为函数调用时,foaObj对象包含并引用它。

当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因此,调用foa函数时this被绑定到foaObj这个对象上,所以this.a 和 foaObj.a 是一样的。

然而,有一个常见的this绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把this绑定到全局对象或undefined上。

function fob() {        console.log(this.a);    }    var fobObj = {        a: "Hello",        fob: fob    }    var focObj = fobObj.fob;    var a = 1; //a是全局对象的属性    focObj();

focObj引用实际上是fob函数,所以this绑定的是全局对象中的a。

3 显式绑定

就像我们刚才看到的那样,在分析隐式绑定时,我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接绑定到这个对象上。

JavaScript提供的绝大多数函数以及你自己创建的所有函数都可以使用call(…) 和 apply (…) 方法。

这两个方法的第一参数是一个对象,是给this准备的,接着在调用函数时将其绑定到this。因为你可以直接指定this的绑定对象,因此我们称之为显式绑定。

function fod() {        console.log(this.a);    }    var fodObj = {        a: 2    }    fod.call(fodObj); //2

通过fod.call(…)方法,可以强制把this绑定到fodObj这个对象上。

然而,显示绑定仍然无法解决之前提出的丢失绑定问题。

但是显示绑定的一个变种可以解决这个问题。

function foh() {        console.log(this.a);    }    var fohObj = {        a: 2    }    var baa = function() {        foh.call(fohObj);    }    baa(); //2    setTimeout(baa, 100); //2    baa.call(window); //2

我们创建了一个baa函数,并在它的内部手动调用了foh.call(fohObj),因此强制把foh的this绑定到了fohObj上。无论之后如何调用函数baa,它总会手动在fohObj上调用foh。这种绑定是一种显示的强制绑定,因此我们称之为硬绑定。

硬绑定的典型应用场景就是创建一个包裹函数,负责接收参数并返回值。

function foi(something) {        console.log(this.a, something);        return this.a + something;    }    var foiObj = {        a: 2    }    var bae = function() {        return foi.apply(foiObj, arguments);    }    var b = bae(3);    console.log(b);

另一种使用方法是创建一个可以重复使用的辅助函数。

function fol(something) {        console.log(this.a, something);        return this.a + something;    }    function bind(fn, obj) {        return function() {            return fn.apply(obj, arguments);        }    }    var folObj = {        a: 3    }    var bac = bind(fol, folObj);    var c = bac(4);    console.log(c);

4 new绑定

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

1) 创建(或者说构造)一个全新的对象。

2) 这个新对象会被执行Prototype连接。
3) 这个新对象会绑定到函数调用的this。
4) 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

function abc(a) {        this.a = a;    }    var x = new abc(10);    console.log(x.a);

转载地址:http://qnfga.baihongyu.com/

你可能感兴趣的文章
在 CentOS7.0 上搭建 Chroot 的 Bind DNS 服务器
查看>>
大型网站的 HTTPS 实践(二):HTTPS 对性能的影响
查看>>
《Swift 权威指南》——第6章,第6.10节嵌套函数
查看>>
《自己动手做交互系统》——1.3 本章小结
查看>>
Mobile devices bundled with malware?
查看>>
《JavaScript面向对象精要》——1.5 访问属性
查看>>
《Python数据可视化编程实战》—— 第 1 章 准备工作环境
查看>>
Android应用性能优化最佳实践.1.1 Android Studio的优势
查看>>
《设计模式解析(第2版•修订版)》—第2章 2.2节什么是UML
查看>>
【直播】APP全量混淆和瘦身技术揭秘
查看>>
10个大坑,当你产品上架AppStore会遇到
查看>>
【shell 脚本】两种登录方式
查看>>
学习编程的方法
查看>>
升级linux自带的Python
查看>>
百度地图2.0瓦片地址获取(窗口内瓦片)
查看>>
我的友情链接
查看>>
.JDK1.6安装配置后的测试
查看>>
判断闰年的函数
查看>>
pkill -9 nginx
查看>>
关于ASP.NET MVC4 Web API简单总结
查看>>