简述this,call,apply,bind之间的关系
一、什么是this?
this是JavaScript语言的一个关键字,它是函数运行时在函数体内部自动生成的一个对象,只能在函数体内部使用。函数的不同使用场合,this的指向不同。
在ES5中,this永远指向最终调用它的对象。
- 例1:
- 这里最终调用函数a的对象是全局window,相当于window.a()。
- 所以this指向window,this.name的值为全局变量name的值 'windowsName'。
- var name = "windowsName";
- function a () {
- var name = "Cherry";
- console.log(this.name); // windowsName
- console.log(this); // [object Window]
- }
- a();
- console.log(this) // [object Window]
- 例2:
- a.fn()调用函数fn的最终对象是a,this指向对象a,所以最终的name值是'skillnull'。
- window.a.fn()调用函数fn的最终对象是a,this指向a,所以最终的name值是'skillnull'。
- 注:由于window下的变量和方法访问和调用的时候可以省略window,所以a.fn() === window.a.fn()。
- b()调用函数fn的最终对象是window,this指向window,所以最终的name值是'windowsName'。这里将a.fn赋值给变量b的时候并没有调用fn。
- var name = "windowsName";
- var a = {
- name: "skillnull",
- fn: function () {
- console.log(this.name);
- }
- }
- a.fn(); // skillnull
- window.a.fn(); // skillnull
- var b = a.fn;
- b(); // windowsName
二、如何改变this的指向?
- 使用 ES6 的箭头函数
箭头函数的 this 始终指向函数定义时的 this,而非执行时。- 例3:
- 注:若setTimeout推迟执行的函数是某个对象的方法,那么该方法中的this关键字将指向全局环境。
- 由此可以看出a.fn2()中被setTimeout推迟执行的函数的最终调用对象是window,this指向window,
- 而window中没有fn1方法,所以最终结果为错误信息:this.fn1 is not a function。
- a.fn3()中被setTimeout推迟执行的函数使用了箭头函数,此时的this指向函数定义时的this,即a,所以最终结果为:skillnull。
- a.fn4()中的函数没有被setTimeout推迟执行,最终对象仍为a,此时的this指向a,所以最终结果为:skillnull。
- var name = "windowsName";
- var a = {
- name: "skillnull",
- fn1: function () {
- console.log(this.name)
- },
- fn2: function () {
- // console.log(this) // a
- setTimeout(function () {
- // console.log(this) // [object Window]
- this.fn1()
- }, 100);
- },
- fn3: function () {
- setTimeout(() => {
- // console.log(this) // a
- this.fn1()
- }, 100);
- },
- fn4: function () {
- this.fn1()
- }
- };
- a.fn2() // this.fn1 is not a function
- a.fn3() // skillnull
- a.fn4() // skillnull
- 例3:
- 在函数内部使用 that = this
- 如果上面例子中的fn2中使用that = this改变一下this的指向,此时that属于fn2的内部变量,指向a,所以最终结果为:skillnull
- fn2: function () {
- var that = this;
- setTimeout(function () {
- // console.log(that) // a
- that.fn1()
- }, 100);
- }
- 如果上面例子中的fn2中使用that = this改变一下this的指向,此时that属于fn2的内部变量,指向a,所以最终结果为:skillnull
- new 实例化一个对象
如果函数调用前使用了 new 关键字, 则是调用了构造函数。这看起来就像创建了新的函数,但实际上 JavaScript 函数是重新创建的对象。new实例化一个对象的过程如下:
1.创建一个空对象 obj;
2.将新创建的空对象的隐式原型指向其构造函数的显示原型。
3.使用 call 改变 this 的指向
4.如果无返回值或者返回一个非对象值,则将 obj 返回作为新对象;如果返回值是一个新对象的话那么直接直接返回该对象。- 伪代码表示:
- var a = new myFunction("Li", "Yafei");
- new myFunction {
- var obj = {};
- obj.__proto__ = myFunction.prototype;
- var result = myFunction.call(obj, "Li", "Yafei");
- return typeof result === 'obj' ? result : obj;
- }
- 伪代码表示:
- 使用 apply、call、bind
- 例4:
- call、apply、bind都可以更改this的指向,三者作用相同。
- 由于a.fn赋值给全局变量b的时候没有执行,上面已经说过,此时的this指向widnow,调用b('skill', 'null')的结果为:i am skillnull
- 而在调用方法b的时候使用call、apply或bind,将此时的this指向a,所以最终结果是:i am not skillnull
- var name = 'i am '
- var a = {
- name: "i am not ",
- fn: function (a, b) {
- console.log(this.name + a + b)
- }
- }
- var b = a.fn;
- b('skill', 'null') // i am skillnull
- b.call(a, 'skill', 'null') // i am not skillnull
- b.apply(a, ['skill', 'null']) // i am not skillnull
- b.bind(a, 'skill', 'null')() // i am not skillnull
- 例4:
三、call、apply、bind 和 this 的关系
从上面的文章可以看出来,其实call、apply、bind最常用的用途是更改this指向。
四、call、apply、bind三者的区别
call和apply不同之处主要在于参数的形式,call参数是一个列表,apply参数是一个数组。
而bind会创建一个新函数,需要手动调用,bind的参数形式和call相同。
注:如果当前函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象)。
简述this,call,apply,bind之间的关系的更多相关文章
- 数组去重,call、apply、bind之间的区别,this用法总结
一.数组去重,直接写到Array原型链上. //该方法只能去除相同的数字 不会去判断24和'24'是不同的 所有数字和字符串数字是相同是重复的 Array.prototype.redup=functi ...
- javascript-this,call,apply,bind简述2
上节我们一起研究了this这个小兄弟,得出一个结论,this指向调用this所在函数(或作用域)的那个对象或作用域.不太理解的朋友可以看看上节的内容,这次我们主要探讨一下call(),apply(), ...
- javascript-this,call,apply,bind简述1
最近在系统的学习面向对象方面的知识,遇到的最大拦路虎就数this的指向,call,apply,bind函数的使用,单独抽出一天时间把这几个烦人的家伙搞定,去学习更深入的内容. 首先介绍一下this的一 ...
- angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。
最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...
- call(),apply(),bind()与回调
1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...
- [工具] slf4j-api、slf4j-log4j12以及log4j之间的关系
几乎在每个jar包里都可以看到log4j的身影,在多个子工程构成项目中,slf4j相关的冲突时不时就跳出来让你不爽,那么slf4j-api.slf4j-log4j12还有log4j是什么关系? ...
- 你不知道的JavaScript--Item9 call(),apply(),bind()与回调
1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...
- 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系
[Linux网络编程]TCP网络编程中connect().listen()和accept()三者之间的关系 基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: conn ...
- Java 8-Lambda表达式、方法引用、标准函数接口与流操作、管道操作之间的关系
1.Lambda表达式与接口之间的关系 只要Lambda表达式的声明形式与接口相一致,在很多情况下都可以替换接口.见如下代码 Thread t1 = new Thread(new Runnable() ...
随机推荐
- Python之requests的安装
在 windows 系统下,只需要输入命令 pip install requests ,即可安装. 在 linux 系统下,只需要输入命令 sudo pip install requests ,即可安 ...
- Python+selenium+pil+tesseract实现自动识别验证码
一.环境搭建准备: 1.Python下载,安装以及环境配置 2.IDE pycharm 工具下载,安装 3.ie浏览器 4.selenium 5.pil:pil第三方库的下载,win下安装whl文件, ...
- Windows下Mongodb安装部署
1.下载安装包 mongodb-win32-x86_64-enterprise-windows-64-3.6.4.zip 解压 安装失败(当前环境windows server2012 R2):已验证可 ...
- POJ 2251 Dungeon Master (三维BFS)
题目链接:http://poj.org/problem?id=2251 Dungeon Master Time Limit: 1000MS Memory Limit: 65536K Total S ...
- ConcurrentHashMap(JDK1.8)为什么要放弃Segment
今天看到一篇博客:jdk1.8的HashMap和ConcurrentHashMap,我想起了前段时间面试的一个问题:ConcurrentHashMap(JDK1.8)为什么要使用synchronize ...
- 238. [LeetCode] Product of Array Except Self
Given an array nums of n integers where n > 1, return an array output such that output[i] is equ ...
- 常用的不易记忆的css自定义代码
在制作页面时,经常会遇到需要自定义一些标签的默认行为(如:input的占位符等),但这些默认的设置的css一般比较难记住,所以有必要自己做一下记录.下面是我经常用到的一些重设默认行为的css. 1.占 ...
- TP框架代码学习 学习记录 3.2.3
文件:think.class.php PHP提供register_shutdown_function()这个函数,能够在脚本终止前回调注册的函数,也就是当 PHP 程序执行完成后执行的函数.regis ...
- 关于解决MySort
关于解决MySort 那天老师教给我们关于sort的用法以及String类中的split方法.在一定程度上告诉我们sort用法的原理和一些特别的用法后,老师叫我们用JAVA尝试去设计一个"M ...
- KNN算法之图像处理一
KNN: 1.数据挖掘分类技术中最简单的方法之一. 2.也称为邻近算法,K最近邻分类算法 3.每个样本都可以用它最接近的k个邻居来代表 4.一般,距离使用欧式距离或曼哈顿距离(通常,k≤20) pyt ...