普通函数

下面这种就是普通函数

function add(x, y) {
return x + y;
}

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

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

function outer() {
function inner() {
console.log(this); // window
}
console.log(this); // 'outer'
inner();
}
outer.call('outer');

相当于:

function outer(_this) {
function inner(_this) {
console.log(_this); // undefined
}
console.log(_this); // 'outer'
inner(undefined);
}
outer('outer');

箭头函数

const add = (x, y) => {
return x + y;
};

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

function outer() {
const inner = () => {
console.log(this); // 'outer'
};
console.log(this); // 'outer'
inner();
}
outer.call('outer');

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

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

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

普通函数作为方法

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

const obj = {
prop: function () {}
};

调用方法的方式是:

obj.prop(x, y)

相当于:

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

陷阱

1 回调函数里面用this

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

performCleanup() {
cleanupAsync()
.then(function () {
this.logStatus('Done'); // (A)
});
}

你应该采用箭头函数:

performCleanup() {
cleanupAsync()
.then(() => {
this.logStatus('Done');
});
}

2 map方法里面用this

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

prefixNames(names) {
return names.map(function (name) {
return this.company + ': ' + name; // (A)
});
}

采用箭头函数:

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

3 用函数作为回调

class UiComponent {
constructor(name) {
this.name = name;
const button = document.getElementById('myButton');
button.addEventListener('click', this.handleClick); // (A)
}
handleClick() {
console.log('Clicked '+this.name); // (B)
}
}

改为:

class UiComponent {
constructor(name) {
this.name = name;
const button = document.getElementById('myButton');
button.addEventListener(
'click', this.handleClick.bind(this)); // (A)
}
handleClick() {
console.log('Clicked '+this.name);
}
}

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

function returnThis() {
return this;
}
const bound = returnThis.bind('hello');
bound(); // 'hello'
bound.call(undefined); // 'hello'

保持正确的做法

1 用ESlint的rules: no-invalid-this

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

2 不要把this当做参数

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

beforeEach(function () {
this.addMatchers({ // access API object
toBeInRange: function (start, end) {
···
}
});
});

可以很容易被改写:

beforeEach(api => {
api.addMatchers({
toBeInRange(start, end) {
···
}
});
});

原文链接: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. W: 无法下载 bzip2:/var/lib/apt/lists/partial/extras.ubuntu.com_ubuntu_dists_trusty_main_source_Sources

    1 错误描述 youhaidong@youhaidong:~$ cd 下载 youhaidong@youhaidong:~/下载$ sudo apt-get update 忽略 http://cn.a ...

  2. 学习笔记:Vue+Node+Mongodb构建简单商城系统(一)

    所需前置知识: HTML.CSS.JS.Vue.ES6.Npm.Webpack.Node.Express.Mongodb 项目整体架构: IDE:webstorm: 项目建立过程(cmd常用命令行指令 ...

  3. 使用图片作为a标签的点击按钮时,当触发touchstart的时候,往往会有一个灰色的背景,想要去掉的话可以用下面这种方式

    a,a:hover,a:active,a:visited,a:link,a:focus{    -webkit-tap-highlight-color:rgba(0,0,0,0);    -webki ...

  4. 总结各类错误(always online)

    最近发现打暴力(还有梦想中的正解)都会打错,决定好好总结一下各种坑比错误QAQ 1.一定要好好看数据范围,接近int类型上限,如果要求和,一定要开long long并且改大你的inf值(TAT暴力分流 ...

  5. 【BZOJ1001】狼抓兔子(网络流)

    [BZOJ1001]狼抓兔子(网络流) 题面 Description 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的, 而且现在的兔子还比较笨, ...

  6. 【POJ 3401】Asteroids

    题面 Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x ...

  7. 使用JSONP实现跨域

    什么是跨域? 简单的来说,出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,即"同源策略".而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通 ...

  8. c# List实现原理

    在研究前辈们写的代码,总是搞不明白.word文中引文的索引和引文列表中的索引对应关系是什么呢?是如何对应上的?我冥思苦想,昨天又系统地看了下代码,才所有悟,所以记录下我的探索过程. 如下图所示: 图1 ...

  9. cocos creator实现棋牌游戏滑动选牌的功能

    最近在玩cocos creator,打算学着做一款类似双扣游戏的棋牌,名字叫文成三星,比双扣还要多一扣,因为需要三幅牌,在我们老家比较流行这种玩法. 目前实现了绝大部分的逻辑效果如下: 有一点不好的体 ...

  10. 小米google play service停止工作解决办法,不root,不刷第三方recovery(也适用于其他的手机)

    问题: 原因是手机安卓系统是6.0.系统应用里面没有包含谷歌框架等一系列谷歌的小东西. 参考: http://www.miui.com/thread-3548436-1-1.html http://w ...