06: JS 中 this 的使用技巧总结

thisJavaScript 中的关键字。

  • 一、基本认识

    在 JS 中我们把 this 关键字当作成一个 快捷方式,用来引用当前调用者。

    解释上面这句话,其实就是一句话:

    this关键字指向的是当前上下文(context)的主体(subject),或者当前正在被执行的代码块的主体。

    通俗一点解释就是: 谁手里拿着这个名字叫 this 的武器,this 就指向拿着这个武器的人。 就好比 说起 屠龙刀 你就能想起 金毛狮王,说起 倚天剑 就能想起 周芷若 一样。 这些武器就是 this,但是 this 代表着谁呢? 代表着拿着这些武器的人。

    但是有一种特殊的情况就是: 如果拿着这个武器的人是一个无名英雄的话,那么这个 this 就会指向 undefined。

eg1:

"use strict"
(function() {
console.log(this) // undefined
})()
对比下 非严格模式下
(function() {
console.log(this) // window
})()
  • 1.1、基本认识 之 严格模式

    严格模式的限制:(大约15条规则)

  • 1.1.1、不允许使用未声明变量

"use strict"
x=123
// Uncaught ReferenceError: x is not defined
...
  • 1.1.15 禁止this关键字指向全局对象
function f() {
console.log(this) // window
} function x() {
"use strict"
console.log(this) // undefined
}
  • 二、this 关键字的核心

如果一个方法内部使用了this关键字,当且仅当对象调用方法时this关键字才会被赋值,而且,当方法被调用时,this的赋值又严格依赖于实际调用这个方法的对象,也就是说,this通常会被赋予调用对象的值

这句话 这么读起来 其实还是比较 拗口的,我们还是拿 `屠龙刀` 举例子吧。

当 金毛狮王 拿起来屠龙刀的时候,这刀才能被赋予神力。如果这把刀被 金毛狮王借给了 张无忌来用的话,也只有当 张无忌 拿起来这把刀的时候,屠龙刀才能被赋予神力。屠龙刀被放在剑鞘里面的时候,是不具备神力的。
  • 三、全局范围内的 this

    在全局域中,代码在浏览器执行,所有变量和方法都属于window对象,因此在全局域中使用this关键字的时候,它会被指向全局变量window对象。

var firstName = 'Peter',
lastName = 'Ally'; function showFullName(){
console.log(this.firstName + ' ' + this.lastName);
} var person = {
firstName : 'foo',
lastName : 'bar',
showFullName : function(){
console.log(this.firstName + ' ' + this.lastName);
}
} showFullName(); //Peter Ally window.showFullName(); //Peter Ally person.showFullName(); //foo bar
  • 四、上下文(context) 和 this 之间的关系

      这里的上下文  在很多情况下  其实是为了能够使其被改变而存在的一个所谓的 上下文。
    
      既然提到了 this 和 上下文 那就无法避免 call apply 和 bind

    下面我们 就来说一说 this 和 bind call apply 之间的关系。

  • 五、this 同 bind 、call、apply 的比较

    5.1 this 和 call


var person = {
fN: 'zhang',
lN: 'san',
getName: function() {
console.log(this.fN + ‘ ’ + this.lN)
}
} var anotherPerson = {
fN: 'li',
lN: 'si'
} person.getName() // zhang san
person.getName.call(anotherPerson) // li si
5.2 this 和 apply

var person = {
firstName : 'foo',
lastName : 'bar',
showFullName : function(){
console.log(this.firstName + ' ' + this.lastName);
}
}; var anotherPerson = {
firstName : 'Peter',
lastName : 'Ally'
}; person.showFullName.apply(anotherPerson) // Peter Ally person.showFullName.call(anotherPerson, 1,2,3)
// Peter Ally
// 1 2 3 person.showFullName.apply(anotherPerson, [1,2,3])
// Peter Ally
// 1 2 3
5.3 this 和 bind
在EcmaScript5中扩展了叫bind的方法(IE6,7,8不支持)
bind与call很相似

var person = {
firstName : 'foo',
lastName : 'bar',
showFullName : function(x,y){
console.log(this.firstName + ' ' + this.lastName);
console.log(x,y)
}
}; var anotherPerson = {
firstName : 'Peter',
lastName : 'Ally'
}; person.showFullName.bind(anotherPerson)(123,456) // Peter Ally
// 123 456
  • 六、this使用技巧

1. 作为回调函数传入其他方法

var user = {
name : 'zhang',
clickHandler : function(){
console.log(this.name);
}
} button.onclick = user.clickHandler; //undefined,无法读取对象的name属性

分析:当把user.clickHandler当作回调函数传入button元素的click事件,user.clickHandler中的this将不再执行user。因为真正调用user.clickHandler的对象是button对象。

当上下文改变时,当我们在其它对象而非原对象上执行某个方法的时候,显然this关键字不再指向定义了this关键字的原对象。

解决方法:使用bind,apply,call来强制保证作用域,即this指向的对象。

  1. bind

    button.onclick = user.clickHandler.bind(user);
  2. apply/call

    button.onclick = function(){
    user.clickHandler.call(user);
    }

2. 闭包中的this

内部方法不能直接使用this关键字来访问外部方法的this变量,因为this变量只能被特定的方法本身使用。

var user = {
tournament: "The Masters",
data: [{
name: "T. Woods",
age: 37
},
{
name: "P. Mickelson",
age: 43
}],
clickHandler: function() {
this.data.forEach(function(person) {
console.log("What is This referring to? " + this);
console.log(person.name + " is playing at " + this.tournament);
})
}
} user.clickHandler(); // What is "this" referring to? [object Window]

为了保证闭包中的this的指向的正确,

var user = {
tournament: "The Masters",
data: [{
name: "T. Woods",
age: 37
},
{
name: "P. Mickelson",
age: 43
}],
clickHandler: function() {
//保存this对象
var that = this;
this.data.forEach(function(person) {
console.log("What is This referring to? " + that);
console.log(person.name + " is playing at " + that.tournament);
})
}
} user.clickHandler(); // What is "this" referring to? [user]

3. 方法被赋值给某个变量

var name = 'global';

var user = {
name : 'user',
showName : function(){
console.log(this.name);
}
} //把方法赋值给变量
var showName1 = user.showName; showName1(); //global //使用bind绑定作用域
var showName2 = user.showName.bind(user); showName2();//user

4. 借用方法带来的问题

/*
下面代码中有两个对象。其中一个定义了avg方法,另一个不包含avg的定义。
我们用另一个对象来借用前一对象的avg方法。
*/
var gameController = {
scores: [20, 34, 55, 46, 77],
avgScore: null,
players: [{
name: "Tommy",
playerID: 987,
age: 23
},
{
name: "Pau",
playerID: 87,
age: 33
}]
} var appController = {
scores: [900, 845, 809, 950],
avgScore: null,
avg: function() {
var sumOfScores = this.scores.reduce(function(prev, cur, index, array) {
return prev + cur;
});
this.avgScore = sumOfScores / this.scores.length;
}
} //原文中的第二参数是多余的,写上会造成理解的误差
appController.avg.apply(gameController); console.log(gameController.avgScore);

Github传送门,欢迎 Star - -

Github地址,欢迎 Star

《前端之路》之 this 的使用技巧总结的更多相关文章

  1. 《前端之路》之 JavaScript 进阶技巧之高阶函数(下)

    目录 第二章 - 03: 前端 进阶技巧之高阶函数 一.防篡改对象 1-1:Configurable 和 Writable 1-2:Enumerable 1-3:get .set 2-1:不可扩展对象 ...

  2. 《前端之路》之 Javascript 模块化管理的来世今生

    目录 第二章 - 04: Javascript 模块化管理的来世今生 一.什么是模块化开发 1-1.模块化第一阶段 1-2.封装到对象 1-3. 对象的优化 二.模块化管理的发展历程 2-1.Comm ...

  3. 《前端之路》之二:数据类型转换 && 隐式转换 || 显式转换

    目录 02:数据类型转换 && 隐式转换 || 显式转换 02:数据类型转换 && 隐式转换 || 显式转换 在上一个章节中,我们介绍了 JavaScript 的基本的 ...

  4. 《前端之路》--- 重温 Egg.js

    目录 <前端之路>--- 重温 Egg.js 一.基础功能 > 日志系统包含了 四大层面的 日志对象, 分别是 App Logger.App CoreLogger.Context L ...

  5. 《前端之路》- TypeScript(二) 函数篇

    目录 一.定义函数方法 二.定义函数传参 三.可选传参 四.默认传参 五.传递剩余参数 六.函数重载 七.箭头函数 八.总结 一.定义函数方法 在 es5 中定时函数的方法有 命名函数和函数表达式(匿 ...

  6. 《前端之路》- TypeScript (三) ES5 中实现继承、类以及原理

    目录 一.先讲讲 ES5 中构造函数(类)静态方法和多态 1-1 JS 中原型以及原型链 例子一 1-2 JS 中原型以及原型链中,我们常见的 constructor.prototype.**prot ...

  7. 《前端之路》- TypeScript (四) class 中各类属性、方法,抽象类、多态

    目录 一.TypeScript 中的类 二.TypeScript 中类的继承 三.TypeScript 中公共,私有与受保护的修饰符 3-1.属性的 public 3-2.属性的 private 3- ...

  8. Web前端之jQuery 的10大操作技巧

    不管是做什么事情,人们习惯在工作中去找方法.找技巧,来帮助提高效率,在软件开发中更是如此.jQuery作为前端开发必学技术之一,在使用中也有各种各样的小技巧,今天小编为大家分享10条必知会的技巧,希望 ...

  9. 前端人员一定要掌握的PS技巧

    一.PS与前端知多少 一般我们会认为PS是用来修改图片的,这些工作是美工人员做的事不是前端人员做的,其实这样想你就错了,因为在前端人员也是要学会一些简单的关于PS的技巧的,这样就不会应为一点点小小的需 ...

随机推荐

  1. IDEA使用教程

    以下内容引自: https://www.cnblogs.com/yjd_hycf_space/p/7483921.html IntelliJ IDEA使用教程(很全) 这个编辑器我就不再多做介绍了.直 ...

  2. MFC中ComboBox控件用法

    MFC ComboBox 一.入门篇 ComboBox (组合框)控件很简单,可以节省空间.从用户角度来看,这个控件是由一个文本输入控件和一个下拉菜单组成的.用户可以从一个预先定义的列表里选择一个选项 ...

  3. bzoj5248 [2018多省省队联测]一双木棋

    直接hash+爆搜即可. #include <cstdio> #include <cstring> #include <iostream> #include < ...

  4. BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS

    BZOJ_2242_[SDOI2011]计算器_快速幂+扩展GCD+BSGS 题意: 你被要求设计一个计算器完成以下三项任务: 1.给定y,z,p,计算Y^Z Mod P 的值: 2.给定y,z,p, ...

  5. 【Unity游戏开发】Lua中的os.date和os.time函数

    一.简介 最近马三在工作中经常使用到了lua 中的 os.date( ) 和 os.time( )函数,不过使用的时候都是不得其解,一般都是看项目里面怎么用,然后我就模仿写一下.今天正好稍微有点空闲时 ...

  6. Error【0003】:配置桥接网络报错

    1.1 问题背景 在配置cosole宿主机的桥接网络环境时,在修改完/etc/sysconfig/ifcg-ethx和/etc/sysconfig/ifcg-brx后,执行service networ ...

  7. Word2Vec总结

    摘要: 1.算法概述 2.算法要点与推导 3.算法特性及优缺点 4.注意事项 5.实现和具体例子 6.适用场合 内容: 1.算法概述 Word2Vec是一个可以将语言中的字词转换为向量表达(Vecto ...

  8. 从壹开始微服务 [ DDD ] 之九 ║从军事故事中,明白领域命令验证(上)

    烽烟 哈喽大家周二好呀,咱们又见面了,上周末掐指一算,距离 圣诞节 只有 5 周的时间了(如果你还不知道为啥我要提圣诞节这个时间点,可以看看我的第二系列开篇<之一 ║ D3模式设计初探 与 我的 ...

  9. .net core 在网络高并发下提高JSON的处理效率

    现有的webapi一般都基于JSON的格式来处理数据,由于JSON是一个文本类的序列化协议所以在性能上自然就相对低效一些.在.net中常用Newtonsoft.Json是最常用的组件,由于提供简便基于 ...

  10. hashCode()方法以及集合中Set的一些总结

    一.前言 本篇文章没有什么主题,就是一些零散点的总结.周末没事看了几道蚂蚁金服的面试题,其中有好几道都是特别简单的,基础性的题目,就是我们平时用到的,但是发现要是完全说出来还是有一些不清楚的地方,所以 ...