This详解

瘢痂范式
• 阅读 1721
this的定义:表示当前执行代码的环境对象

因此可将 this 的剖析分为“全局环境” 和 “函数环境” 两种类型的环境对象

一、全局环境

console.log(this === window); // true 

var a = 10;
console.log(this.a); // 10

二、函数环境

在函数内部,this 的取值取决于函数被调用时的运行环境。

这里涉及到内存里的数据结构相关的知识点,当我们定义以下字面量对象时会发生一系列的关联关系

var obj = { name: 'Tom' };

javascript 引擎会先在内存中生成 { name: 'Tom' } 对象,接着再把这个对象的内存地址赋值给 obj 变量,所以 obj 变量保存的只是一个内存地址而已,如果要获取 obj.name,javascript 引擎会先从 obj 变量中拿到内存地址,然后从该地址中获取原始对象,再返回 name 属性。

而属性值为函数时,该函数会被保存在内存中,然后将该内存地址赋值给该属性,因此该地址赋值给不同环境执行时它的作用域是不一样的,而 this 对象就是指向函数当前的执行环境对象,执行环境是会在 Event Loop(事件循环)过程中变化的,因此 this 在函数环境下是属于运行时的。

var name = 'Tom'; 

var obj = { 
    name: 'Iceberg', 
    say: function() { 
        console.log('my name is ' + this.name); 
    }, 
    sub: { 
        say: function() { 
            console.log('my name is ' + this.name); 
        } 
    } 
}; 

obj.say(); // my name is Iceberg 
obj.sub.say() // my name is undefined; 

var say = obj.say; 
say(); // my name is Tom;

上面的例子说明 obj.say() 执行环境为 obj 对象,而 obj.sub.say() 的执行环境却是 obj.sub 对象,而对于 obj.sub 来说并没有 name 属性,因此为 undefined;而 var say = obj.say; 则表示将 say 方法的内存地址赋值给全局变量,因此从全局变量 name 中取值。


运用场景

接下来从 this 在函数环境下的不同运用场景来剖析

1.事件回调函数

var handler = { 
    nickname: 'anonymous', 
    register: function() { 
      console.log(this.nickname); 
    } 
} 
$('#registerBtn').on('click', handler.register); // undefined

以上逻辑点击触发后输出的是 undefined,因为函数被当做事件触发的回调函数执行时,this 是指向该触发事件对应的元素,如要 this 仍然以 handler 对象为执行环境,则可使用函数的 bind 方法进行执行环境对象的绑定操作。

$('#registerBtn').on('click', handler.register.bind(handler)); // anonymous

2.构造函数
要理解 this 在构造函数中的逻辑就要理清楚构造函数在实例化过程中都发生了什么。

1.  function A() { 
2.  this.name = 'Tom'; 
3.  this.age = 20; 
4.  } 
5.  var a = new A();

使用 new 命令实例化构造函数 A 的过程中会发生以下流程:

1.创建一个空对象,作为将要返回的对象实例
2.将该空对象的原型指向构造函数的 prototype 属性
3.将该空对象赋值给构造函数内部的 this 关键字
4.执行构造函数内部代码
5.默认返回 this 对象(如 return 的为非对象类型,如数字 123,会被忽略进而默认 return this 对象)
6.由以上逻辑可知道 this 关键字在构造函数中表示的是其实例对象。

bind

1.  function A() { 
2.  this.nickname = 'Tom'; 
3.  this.say = function() { 
4.  console.log(this.nickname); 
5.  } 
6.  } 
7.  var b = { nickname: 'John' }; 
8.  var a = new A(); 
9.  var say = a.say; 
10. var say1 = a.say.bind(a); 
11. var say2 = a.say.bind(b);
12. say(); // undefined
13. say1(); // Tom
14. say2(); // John

call&apply

1.  function A() { 
2.  this.name = 'Tom'; 
3.  this.sayName = function(){ 
4.  console.log(this.name); 
5.  }; 
6.  } 

8.  function B() { 
9.  this.name = 'John'; 
10.  } 

12.  var a = new A(); 
13.  a.sayName.call(new B()); // John

总结:
1.在一般函数中使用this指全局对象window
2.作为对象方法使用时,this指向该对象
3.作为构造函数使用时,this指向new出的实例
4.apply或call使用时,此方法第一个参数为改变后的调用函数的对象,函数里this指第一个参数。
5.被当做事件触发的回调函数执行时,this 是指向该触发事件对应的元素

题外:手写一个new操作

//新建一个类
function Otaku(name, age) {
    this.name = name;
    this.age = age;
    //自身的属性
    this.habit = 'pk';
}
//给类的原型上添加属性和方法
Otaku.prototype.strength = 60;
Otaku.prototype.sayYourName = function() {
    console.log('I am' + this.name);
}
//实例化一个person对象
const person = new Otaku('cty', 5000);
person.sayYourName();
console.log(person);
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
10个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Stella981 Stella981
4年前
JS 中的this指向问题和call、apply、bind的区别
this的指向问题一般情况下this对象指向调用函数的对象,全局环境中执行函数this对象指向window。functiona(){console.log(this);//输出函数a中的this对象}functionb(){};varc{name:"call"}
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
瘢痂范式
瘢痂范式
Lv1
行多有病住无粮,万里还乡未到乡。
文章
4
粉丝
0
获赞
0