普通函数

下面这种就是普通函数

  1. function add(x, y) {
  2. return x + y;
  3. }

每个普通函数被调用的时候,都相当于有一个this参数传进来。

内部函数this不会是外部函数传入的this,相当于和外部的this隔离开了。

  1. function outer() {
  2. function inner() {
  3. console.log(this); // window
  4. }
  5. console.log(this); // 'outer'
  6. inner();
  7. }
  8. outer.call('outer');

相当于:

  1. function outer(_this) {
  2. function inner(_this) {
  3. console.log(_this); // undefined
  4. }
  5. console.log(_this); // 'outer'
  6. inner(undefined);
  7. }
  8. outer('outer');

箭头函数

  1. const add = (x, y) => {
  2. return x + y;
  3. };

如果你用箭头函数,内部函数的this和外部是一致的:

  1. function outer() {
  2. const inner = () => {
  3. console.log(this); // 'outer'
  4. };
  5. console.log(this); // 'outer'
  6. inner();
  7. }
  8. outer.call('outer');

箭头函数的this不会被call方法影响,它总是和箭头函数所在的位置有关:

它所在的位置(也就是作用域)的this指向谁,箭头函数里面的this就指向谁。

  1. function ordinary() {
  2. const arrow = () => this;
  3. console.log(arrow.call('goodbye')); // 'hello'
  4. }
  5. ordinary.call('hello');

普通函数作为方法

如果一个函数赋值给了属性,就变成了方法:

  1. const obj = {
  2. prop: function () {}
  3. };

调用方法的方式是:

  1. obj.prop(x, y)

相当于:

  1. obj.prop.call(obj, x, y)

陷阱

1 回调函数里面用this

回调里面执行(A),你发现logStatus访问不了。这个是因为this被阻隔了。

  1. performCleanup() {
  2. cleanupAsync()
  3. .then(function () {
  4. this.logStatus('Done'); // (A)
  5. });
  6. }

你应该采用箭头函数:

  1. performCleanup() {
  2. cleanupAsync()
  3. .then(() => {
  4. this.logStatus('Done');
  5. });
  6. }

2 map方法里面用this

同理,this也是访问不了company和name的

  1. prefixNames(names) {
  2. return names.map(function (name) {
  3. return this.company + ': ' + name; // (A)
  4. });
  5. }

采用箭头函数:

  1. // Inside a class or an object literal:
  2. prefixNames(names) {
  3. return names.map(
  4. name => this.company + ': ' + name);
  5. }

3 用函数作为回调

  1. class UiComponent {
  2. constructor(name) {
  3. this.name = name;
  4. const button = document.getElementById('myButton');
  5. button.addEventListener('click', this.handleClick); // (A)
  6. }
  7. handleClick() {
  8. console.log('Clicked '+this.name); // (B)
  9. }
  10. }

改为:

  1. class UiComponent {
  2. constructor(name) {
  3. this.name = name;
  4. const button = document.getElementById('myButton');
  5. button.addEventListener(
  6. 'click', this.handleClick.bind(this)); // (A)
  7. }
  8. handleClick() {
  9. console.log('Clicked '+this.name);
  10. }
  11. }

bind函数能让普通的函数调用无法修改this:

  1. function returnThis() {
  2. return this;
  3. }
  4. const bound = returnThis.bind('hello');
  5. bound(); // 'hello'
  6. bound.call(undefined); // 'hello'

保持正确的做法

1 用ESlint的rules: no-invalid-this

避免普通函数内部有this,一般在方法内使用this或者箭头函数内使用

2 不要把this当做参数

因为这样你就不能用箭头函数了

  1. beforeEach(function () {
  2. this.addMatchers({ // access API object
  3. toBeInRange: function (start, end) {
  4. ···
  5. }
  6. });
  7. });

可以很容易被改写:

  1. beforeEach(api => {
  2. api.addMatchers({
  3. toBeInRange(start, end) {
  4. ···
  5. }
  6. });
  7. });

原文链接:http://2ality.com/2017/12/alternate-this.html

作者知乎/公众号:前端疯 (一群热爱前端的一线程序员维护,想要用前端改变世界。)

(译文)掌握JavaScript基础--理解this关键字的新思路的更多相关文章

  1. JavaScript闭包理解【关键字:普通函数、闭包、解决获取元素标签索引】

    以前总觉得闭包很抽象,很难理解,所以百度一下"闭包"概览,百度的解释是:“闭包是指可以包含自由(未绑定到特定对象)变量的代码块:这些变量不是在这个代码块内或者任何全局上下文中定义的 ...

  2. JavaScript基础——理解变量作用域

    一旦你开始在JavaScript应用程序中添加条件.函数和循环,就需要理解变量作用域.变量作用域规定了如何确定正在执行的代码行上的一个特定变量名的值. JavaScript允许你既定义全局版本又定义局 ...

  3. JavaScript闭包理解【关键字:普通函数、变量访问作用域、闭包、解决获取元素标签索引】

        一.闭包(Closure)模糊概述 之前总觉得闭包(Closure)很抽象而且难理解,百度一下"闭包"名词,百度的解释是:“闭包是指可以包含自由(未绑定到特定对象)变量的代 ...

  4. (译文)JavaScript基础——JavaScript中的深拷贝

    在JavaScript中如何拷贝一个对象? 通过引用调用 function mutate(obj) { obj.a = true; } const obj = {a: false}; mutate(o ...

  5. javascript基础 之 保留关键字

    1,保留关键字 意思是:特定的字符串要么是已经有指代了要么是未来将要有指代,所以取名字不要用保留关键字里的字符串 js保留关键字 abstract arguments boolean break by ...

  6. JavaScript基础理解及技巧(入门)

    1.java和JavaScript的区别: (1)js只需要解释就可以执行了,而java需要先编译成字节码文.JavaScript的运行只需要浏览器的支持,而java的运行需要JVM(java虚拟机) ...

  7. 转载 深入理解JavaScript中的this关键字

    转载原地址: http://www.cnblogs.com/rainman/archive/2009/05/03/1448392.html 深入理解JavaScript中的this关键字   1. 一 ...

  8. 如何理解JavaScript中的this关键字

    前言 王福朋老师的 JavaScript原型和闭包系列 文章看了不下三遍了,最为一个初学者,每次看的时候都会有一种 "大彻大悟" 的感觉,而看完之后却总是一脸懵逼.原型与闭包 可以 ...

  9. 理解javascript中的with关键字

    说起js中的with关键字,很多小伙伴们的第一印象可能就是with关键字的作用在于改变作用域,然后最关键的一点是不推荐使用with关键字.听到不推荐with关键字后,我们很多人都会忽略掉with关键字 ...

随机推荐

  1. TypeError: Error #1006: value 不是函数。

    1.错误原因 TypeError: Error #1006: value 不是函数. at BasicChart/dataFunc()[E:\Flash Builder\Map\src\BasicCh ...

  2. OpenStack_I版 5.Nova部署

    Nova安装 创建配置存放目录,日志存放目录,执行文件目录,虚拟机目录  Nova配置修改 生成主配置文件 创建Nova数据库 同步Nova数据库 验证 Nova连接RabbitMQ配置修改  key ...

  3. Django学习-14-分页功能实例

    首先创建一个制作page的工具类                     utils                         --page_make.py                    ...

  4. VS2017 启动调试报错:ID为{....}进程未启动解决方案

    今天遇到这么一个问题,打开VS启动调试,始终报错,如下图: 我重启VS,甚至重启电脑都不得行,那个进程号还在变化,就在网上查找资料,各式各样的解决方案,这里我记录我成功的方案. 打开项目文件地址,在解 ...

  5. 从零一起学Spring Boot之LayIM项目长成记(六)单聊群聊的实现

    文章传送门: https://my.oschina.net/panzi1/blog/1577007 并没有放弃博客园,只是 t-io 在 oschina发展.用了人家的框架,也得帮人家做做宣传是吧~~

  6. 【HNOI2004】宠物收养所(splay)

    题面 Description 最近,阿Q开了一间宠物收养所.收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物.每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的 ...

  7. mysql mariadb 删除表中的数据时数据库变大

    删除表中数据以前 [root@RM uar3]# du -sh * 3.3G apache-tomcat-7.0.54 150M instalRM4UAR 0 mariadb 903M mariadb ...

  8. postgresql搭建从库

    postgresql搭建从库 master  10.40.196.27 slave   10.40.55.69 需求:master和slave作为主从流复制,当master宕机后,slave切换为新主 ...

  9. xx-net连接教程

    第一步:安装xx-net 在github上下载xx-net,网址 解压后点击运行start.bat文件,此时会提醒是不信任的文件,此时在系统偏好设置里的安全性与隐私去设置让它能打开. 第二步:安装Sw ...

  10. ES2015 类 class 语法

    在ES2015之前,定义类的方法只能通过原型链来模拟 function Animal(family,species) { this.family = family; this.species = sp ...