this - 想说爱你不容易

news/2024/9/17 16:43:21

前言

javascript中的this是啥东西?为啥我们经常被他搞得晕头转向不知所以?他是恶魔?是天使 ?是怪胎?让我们一起来揭开它那神秘的面纱。

<!--more-->

他是个啥

首先this是Javascript语言的关键字之一,指函数运行时的当前对象。那既然和函数运行有关,js中函数有哪些调用模式呢?

  1. 纯粹的函数调用

  2. 对象的方法调用

  3. 构造函数调用

  4. apply、call调用

我擦,有木有一千只草泥马在心里蹦腾不息,人家是要弄懂this,你这又是整的哪一出

我们慢慢来,一步步从这些调用模式中探究this这个神奇的远古神兽

纯粹的函数调用

函数调用 即 functionName () 模式,这也是我们使用的最多的一种方式,其属于全局调用,浏览中默认情况下函数内部的this指向window,当然是在非严格模式下。

this.name = 'qianlong';function showName () {console.log(this.name);console.log(this === window);
}showName() // qianlong
// true

对象的方法调用

当一个函数作为对象的某个属性方法被调用的时候

var obj = {name: 'qianlong',showName: function () {console.log(this.name);}
};obj.showName();
// qianlong

可以看出this指向是obj这个对象,其实本质上讲函数调用形式内部this就是指向调用它的那个对象

上面的例子相当于

window.showName()

这也是为什么可以读取到全局定义的name属性的原因。

再来

var showName = function () {console.log(this.name);},obj = {name: 'qianlong',showName: showName};obj.showName();

这个时候输出的是什么呢

结果是不变的,在js中,一切都是对象,而这里也只是将,obj的showName属性指向,showNmae函数的引用地址。

继续

当我们把showName方法赋值给了一个变量,又会有什么事情发生呢?

var obj = {name: 'qianlong',showName: function () {console.log(this.name);}
};var tempShowName = obj.showName;tempShowName()// undefined

为什么不是期望的那样输出 qianlong呢。obj的showName方法是一个对象,当把它赋值给了tempShowName变量,此时便和obj没有什么关系了,而这个时候的调用和下面是等价的。

window.tempShowName()

window上此事并没有name属性,自然输出是undefined

构造函数调用

当使用 new 去调用一个构造函数的时候,内部的this,指向的是实例化出来的对象。

var Person = function (name, sex) {this.name = name;this.sex = sex;console.log(this);
};var p1 = new Person('qianlong', 'boy');// Person {name: 'qianlong', sex: 'boy'};

构造函数也是函数,所以当你用普通调用方式调用时

var Person = function (name, sex) {this.name = name;this.sex = sex;console.log(this);
};Person('qianlong', 'boy');// 这个时候相当于给window对象添加了name和sex两个属性。window.name // 'qianlong'
window.sex // 'boy'

apply、call调用

使用call和apply方式去调用一个函数的时候,内部的this指向的是传进来的第一个参数,当第一个参数是undefined或者null的时候,依旧指向window

关于call和apply欢迎查看另一篇文章

js中call、apply、bind那些事

var showName = function () {console.log(this);};showName() // window
showName.call(undefined) // window
showName.call(null) // window
showName.call({name: 'qianlong'}) // {name: 'qianlong'}

箭头函数

在 ES6 的新规范中,加入了箭头函数,它和普通函数最不一样的一点就是 this 的指向,普通函数中的this,是运行时候决定的,而箭头函数却是定义时候就决定了。

var obj = {name: 'qianlong',showName: function () {console.log(this.name);},showNameLater: function () {setTimeout(() => {console.log(this.name);}, 1000)}        
};obj.showNameLater();// qianlong
var obj = {name: 'qianlong',showName: () => {console.log(this.name);}
};obj.showName();
// undefined

一些坑

1. setTimeout

var obj = {name: 'qianlong',showName: function () {console.log(this.name);},showNameLater: function () { setTimeout(this.showName, 1000);}
};obj.showNameLater();// undefined

这里在执行setTimeout这个函数的时候传了obj的showName函数作为第一个参数,其效果与

var showName = obj.showName

是相同的。而setTimeout内部其实也是执行了传进去这个函数而已,即。

showName();

还记得这种调用方式和window.showName()是类似的效果吗?这个时候输入为undefined也就好理解了。

那么怎么解决这个问题呢,毕竟我们期望的效果是输出qianlong

var obj = {name: 'qianlong',showName: function () {console.log(this.name);},showNameLater: function () { var self = this;setTimeout(function () {self.showName();}, 1000);}
};obj.showNameLater();

或者

var obj = {name: 'qianlong',showName: function () {console.log(this.name);},showNameLater: function () { setTimeout(this.showName.bind(this), 1000);}
};obj.showNameLater();

2. setTimeout

尼玛坑爹啊,居然还是因为你。

'use strict';function show() {console.log(this);
}show(); // undefined setTimeout(show, 1); // window

在严格模式下面,函数调用的时候没有指定this的情况下,内部this的表现为undefined,但是setTimeout却不同,其内部默认还是指向window。

3. 为构造函数指定this

var Person = function (name, sex) {this.name = name;this.sex = sex;
};var p1 = new Person.call({});// Uncaught TypeError: Person.call is not a constructor

这里报错了,原因是我们去 new 了 Person.call 函数 ,这里的函数不是一个构造函数;

当然解决方式也是有的。

var Person = function (name, sex) {this.name = name;this.sex = sex;
};var p1 = new (Person.bind({}))('qianlong', 'sex');// Person {name: "qianlong", sex: "sex"}

4. 为箭头函数指定this

var show = (str) => {console.log(str);console.log(this);
};show('qianlong');
// qianlong
// windowshow.call({name: 'qianlong'}, 'qianlong');
// qianlong
// window

可以看到使用call来手动改变箭头函数中的this的时候,无法成功。 箭头函数中的 this 在定义它的时候已经决定了(执行定义它的作用域中的 this),与如何调用以及在哪里调用它无关,包括 (call, apply, bind) 等操作都无法改变它的 this。

结语

文章可能有些疏漏与错误之处,欢迎各位指正。


http://lihuaxi.xjx100.cn/news/243144.html

相关文章

HP 服务器 iLO 远程控制软件 介绍

iLO了解&#xff1a;iLO 是一组芯片&#xff0c;内部是vxworks的嵌入操作系统,在服务器的背后有一个标准RJ45口对外连接生产用交换机或者带外管理的交换机。iLO 全名是 Integrated Lights-out&#xff0c;它是惠普某些型号的服务器上集成的远程管理端口&#xff0c;它能够允许用…

Python培训:Python内置数据结构之双向队列

经常听说Python就是一门执行速度低的语言&#xff0c;可能是你的程序中使用了复杂的算法与数据结构&#xff0c;才会导致程序执行速率低的。在Python的标准库中提供了常见的数据结构工开发者使用&#xff0c;不仅执行速率比较快&#xff0c;还可以简化开发者的编程工作。下面我…

Apache工具类ToStringBuilder用法简介

ToStringBuilder比较适合在打日志时&#xff0c;输出参数的信息&#xff0c;特别是在参数为对象时&#xff0c;该工具类能够很方便的自动打印对象中的属性值。 package test; /** * * author zhengtian * time 2012-6-28 */ public class User { privat…

JEECMS的新浪图集在IE9、10不能显示大图片BUG的解决方法

2019独角兽企业重金招聘Python工程师标准>>> 最近我给学校对外交流合作处做的网站&#xff0c;因为是学java开发&#xff0c;所以就基于JEECMS去做。等到项目做好&#xff0c;差不多要 交工的时候&#xff0c;发现jeecms的图集在IE9、10(还有某些IE8)在IE下居然居然…

linux下mysql的root密码忘记解决方法

1&#xff0e;首先确认服务器出于安全的状态&#xff0c;最安全的状态是到服务器的Console上面操作&#xff0c;并且拔掉网线&#xff0c;或者可以使用--skip-networking限制只能从本地连接2&#xff0e;修改MySQL的登录设置&#xff1a; # vim /etc/my.cnf在[mysqld]的段中加上…

ps aux|grep

ps a 显示现行终端机下的所有程序&#xff0c;包括其他用户的程序。 2&#xff09;ps -A 显示所有程序。 3&#xff09;ps c 列出程序时&#xff0c;显示每个程序真正的指令名称&#xff0c;而不包含路径&#xff0c;参数或常驻服务的标示。 4&#xff09;ps -e 此参数的效果…

【Python培训基础】一篇文件教你py文件打包成exe

场景: 如果要将我们编写好的代码给别人使用,如果要他们直接使用我们的代码,就需要安装各种编译软件以及第三方模块,还要对软件操作,编程有一定的了解,这对使用者的要求比较高,不是很方便,为了解决这一问题,我们可以选择将我们编写的代码,编译成一个可执行文件,这样,就可以实现跨…

我对于js注入的理解

资料&#xff1a;http://blog.csdn.net/gisredevelopment/article/details/41778671 js注入就是在前端利用使用js的地方 在这其中注入你写的js代码 使其能盗取网站的信息 例子&#xff1a;就像你的网站登录是用js写的 那么利用这个在用户输入账号密码的之后的这段JS中输入你获取…