码文不易,转载请带上本文链接,感谢~ https://www.cnblogs.com/echoyya/p/14506269.html

this 的指向

“this” 关键字允许在调用函数或方法时决定哪个对象应该是焦点。

在JavaScript中this可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式,this 绑定的对象即函数执行的上下文环境,在 ES5 中,其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象,正是由于调用function的对象不同,才导致了this的指向不同。

关于this的指向及绑定,请关注博文 JS五种绑定彻底弄懂this,默认绑定、隐式绑定、显式绑定、new绑定、箭头函数绑定详解

// e.g.1
var test = {
a: 5,
b: 6,
sum: function (a, b) {
function getA(a) {
this.a = a; // 在window上增加了一个全局变量a
return this.a; // 此处this = window
} function getB(b) {
this.b = b; //在window上增加了一个全局变量b
return this.b; // 此处this = window
}
return getA(a) + getB(b);
}
}
console.log(test.sum(4, 3)); // 7
console.log(a); // 4 (打印结果为 window.a)
console.log(b); // 3 (打印结果为 window.b)
// e.g.2
var user = {
name: 'Echoyya',
age: 27,
greet() {
console.log(this.name)
},
bf: {
name: 'KK.unlock',
greet() {
console.log(this.name)
}
}
} user.greet() // Echoyya
user.bf.greet() // KK.unlock

如果 greet 函数不是 user 对象的函数,只是一个独立的函数。

function greet () {
console.log(this.name)
} var user = { name: 'Echoyya' }

如何能让 greet 方法调用的时候将 this 指向 user 对象?不能再像之前使用 user.greet(),因为 user 并没有 greet 方法。我们可以通过一些方法去改变this的指向

怎样改变 this 的指向

(1)使用ES6中箭头函数

箭头函数中的 this 始终指向函数定义时的 this,而非执行时。箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。

也正因如此,箭头函数不能用于构造函数

var name = "windowsName";

var obj = {
name: "Echoyya",
func1: function () {
console.log(this.name)
},
func2: () => {
console.log(this.name)
}
}; obj.func1() // Echoyya obj.func2() // windowsName

(2)函数内部使用 _this = this

如果不使用 ES6,那么这种方式应该是最简单且不易出错的方式了,先将调用这个函数的对象保存在变量 _this 中,然后在函数中都使用这个 _this

obj调用functhis 指向obj,防止setTimeout 被 window 调用,导致 setTimeout 中的 this 指向 window,设置 var _this = this,将 this(指向变量 obj) 赋值给一个变量 _this,这样,在 func 中使用_this 就指向对象 obj

var name = "windowsName";

var obj = {
name: "Echoyya",
func: function () {
var _this = this;
setTimeout(function () {
console.log(_this.name)
}, 1000);
}
}; obj.func() // Echoyya

(3)使用call,apply,bind方法

call、apply、bind 方法是每个函数都有的一个方法,允许在调用函数时为函数指定上下文。可以改变 this 指向

call 与 apply
  • call 方法,第一个参数会作为函数被调用时的上下文。即this 指向传给 call 的第一个参数。
  • 传递参数给使用 .call 调用的函数时,需要在指定上下文(第一个参数)后一个一个地传入。
  • 语法:fun.call(thisArg [, arg1[, arg2[, ...]]])

站在函数应用的角度我们知道了call与apply的用途,那这两个方法又有什么区别呢,其实区别就一点,参数传递方式不同。

  1. call方法中接受的是一个参数列表,第一个参数指向this,其余的参数在函数执行时都会作为函数形参传入函数。

    • 语法:fn.call(this, arg1, arg2, ...);
  2. 而apply不同的地方是,除了第一个参数作为this指向外,其它参数都被包裹在一个数组中,在函数执行时同样会作为形参传入。

    • 语法:fn.apply(this, [arg1, arg2, ...]);

除此之外,两个方法的效果完全相同:

var o = {
a: 1
}; function fn(b, c) {
console.log(this.a + b + c);
};
fn.call(o, 2, 3); // 6
fn.apply(o, [2, 3]); //6
关于 bind

bind要单独说一下,因为它与call,apply还不太一样。call与apply在改变this的同时,就立刻执行,而bind绑定this后并不会立马执行,而是返回一个新的绑定函数,需要在执行一下。

var o = {
a: 1
}; function fn(b, c) {
console.log(this.a + b + c);
}; var fn2 = fn.bind(o, 2, 3); fn2(); //6
var name = 'windowsName'

function greet () {
console.log(this.name)
} var user = { name: 'Echoyya' } greet() // windowsName
greet.bind()() // windowsName (非严格模式下,默认指向window)
greet.bind(user)() // Echoyya
var obj = {
name: "Echoyya",
func: function () {
setTimeout(function () {
console.log(this.name)
}.bind(obj)(), 100);
}
}; obj.func() // Echoyya
call、apply、bind 区别

call、apply、bind 都是可以改变 this 的指向的,但是这三个函数稍有不同。

var test = {
a: 5,
b: 6,
sum: function (a, b) {
var self = this; function getA() {
return self.a;
} function getB() {
return self.b;
}
console.log(a, b); // call, apply, bind 传入参数
return getA() + getB();
}
}
var obj = {
a: 2,
b: 3
}; console.log(test.sum.call(obj, 4, 5)); // 4,5,5 (self = this = obj)
console.log(test.sum.apply(obj, [6, 7])); // 6,7,5 (self = this = obj)
console.log(test.sum.bind(obj, 8, 9)()); // 8,9,5 (self = this = obj)

apply 和 call 的区别

  • .apply.call 本质相同,他们的区别只是传入的参数不同。

    • 传递参数给使用 .call 调用的函数时,需要在指定上下文(第一个参数)后一个一个地传入(参数列表)。
    • 传递参数给使用 .apply 调用的函数时,可以用数组传参而且 .apply 会在函数中自动展开(参数数组)。

call、apply、bind到底有什么区别?bind返回的方法还能修改this指向吗?

  1. apply与call是函数应用,指定this的同时也将方法执行,bind不同,它只是负责绑定this并返回一个新方法,不会执行。

  2. 尝试打印返回的新函数fn2,可以看到它并不是一个普通的function,而是一个bound function,简称绑定函数

    • TargetFunction 指向 bind 前的函数
    • BoundThis 是绑定的 this 指向
    • BoundArgs 是传入的其它参数了

  3. 当我们执行fn2时,有点类似于TargetFunction.apply(BoundThis,BoundArgs)。可以得出一个结论,当执行绑定函数时,this指向与形参在bind方法执行时已经确定了,无法改变。

  4. bind多次后执行,函数this还是指向第一次bind的对象。

    var o1 = { a: 1 };
    var o2 = { a: 2 }; function fn(b, c) {
    console.log(this.a + b + c);
    }; var fn1 = fn.bind(o1, 2, 3); //尝试再次传入形参
    fn1(4, 4); //6 //尝试改变this
    fn1.call(o2); //6 //尝试再次bind
    fn1.bind(o2, 1, 1)() // 6

其实很好理解,当执行fn1时,本质上等于window.fn1(),如果this还能被改变,那this岂不是得指向window,那bind方法就没太大意义了。

一文搞懂 this、apply、call、bind的更多相关文章

  1. 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质

    一文搞懂RAM.ROM.SDRAM.DRAM.DDR.flash等存储介质 存储介质基本分类:ROM和RAM RAM:随机访问存储器(Random Access Memory),易失性.是与CPU直接 ...

  2. 基础篇|一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

  3. 一文搞懂 Prometheus 的直方图

    原文链接:一文搞懂 Prometheus 的直方图 Prometheus 中提供了四种指标类型(参考:Prometheus 的指标类型),其中直方图(Histogram)和摘要(Summary)是最复 ...

  4. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  5. 一文搞懂vim复制粘贴

    转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...

  6. 三文搞懂学会Docker容器技术(中)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 6,Docker容器 6.1 创建并启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] --na ...

  7. 三文搞懂学会Docker容器技术(下)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...

  8. 一文搞懂所有Java集合面试题

    Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...

  9. 一文搞懂 js 中的各种 for 循环的不同之处

    一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...

  10. 一文搞懂如何使用Node.js进行TCP网络通信

    摘要: 网络是通信互联的基础,Node.js提供了net.http.dgram等模块,分别用来实现TCP.HTTP.UDP的通信,本文主要对使用Node.js的TCP通信部份进行实践记录. 本文分享自 ...

随机推荐

  1. OpenStack Train版-11.安装horizon服务(计算节点)

    OpenStack仪表板Dashboard服务的项目名称是Horizon,它所需的唯一服务是身份服务keystone,开发语言是python的web框架Django. 安装Train版本的Horizo ...

  2. 缓冲区溢出实验 1 strcpy

    实验代码 https://github.com/TouwaErioH/security/tree/master/stack%20overflow 实验目的 Buffer over flow 漏洞利用实 ...

  3. P3373 线段树2(多重标记线段树)题解

    题意: 操作有:区间加,区间乘,区间询问求和 思路: 设一个数为\(m*sum+a\),加就变成了\(m*sum+a+a_2\),乘就变成了\(m*m_2*sum+a*m_2\),所以我们设两个标记\ ...

  4. Apple iOS 触控按钮 自动关闭 bug

    Apple iOS 触控按钮 自动关闭 bug bug 轻点 iPhone 背面可执行操作 您可以轻点两下或轻点三下 iPhone 背面以执行某些操作,如向上或向下滚动.截屏.打开"控制中心 ...

  5. Interview Questions All In One

    Interview Questions All In One web fullstack System Design Operating System Object-Oriented Design O ...

  6. js bitwise operation all in one

    js bitwise operation all in one 位运算 & 按位与 | 按位或 ^ 按位异或 / XOR let a = 5; // 000000000000000000000 ...

  7. free useful skills videos courses & tutorials

    free useful skills videos courses & tutorials website video courses https://realpython.com/ http ...

  8. VSCode & disable telemetry reporting

    VSCode & disable telemetry reporting https://code.visualstudio.com/docs/supporting/faq#_how-to-d ...

  9. git merge & git rebase

    git merge & git rebase bug error: You have not concluded your merge (MERGE_HEAD exists). hint: P ...

  10. html5 useful skills blogs

    html5 useful skills blogs preload & prefetch https://www.30secondsofcode.org/snippet/ary blogs h ...