普通函数

下面这种就是普通函数

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. Error:dojo.data.ItemFileWriteStore:Invalid item argument

    1.错误描述 dijit.form.ComboBox TypeError:_4e is undefined                                            Sea ...

  2. 7.C++类与封装的概念

    类通常分为以下两部分 -类的内部具体实现 -类的外部使用方法 比如: 用户使用手机,只需要知道如何使用. 而手机开发者,则需要考虑手机内部的实现细节. 类的封装 并不是类的每个成员变量和成员函数都要对 ...

  3. 芝麻HTTP:非关系型数据库存储

    NoSQL,全称Not Only SQL,意为不仅仅是SQL,泛指非关系型数据库.NoSQL是基于键值对的,而且不需要经过SQL层的解析,数据之间没有耦合性,性能非常高. 非关系型数据库又可细分如下. ...

  4. Angular21 动态绑定CSS样式

    1 需求 在前端开发中通常需要动态对某些元素的样式进行动态设定,传统的CSS绑定分为CSS类绑定和Style样式绑定:在Angular中利用相关指令同样可以完成CSS类绑定和CSS样式绑定 2 内置指 ...

  5. Win Form不能响应键盘事件

    在窗体属性中,将KeyPreview设置为true

  6. 配置maven环境出现ARP tomcat native library 版本安装跟需求版本不一致时的解决方法An incompatible version xxxx of the APR based Apache Tomcat Native library is installed, while Tomcat requires version xxxx

    此地址下载你所需要的library版本http://archive.apache.org/dist/tomcat/tomcat-connectors/native/ 点击binaries 点win32 ...

  7. java保留小数点后位数以及输出反转数字

    //方法一double b = 8.0/3.0; //与C语言不同,此处8.0和8有所区分 String format = String.format("%.2f,b"); //表 ...

  8. ajax错误处理 500错误

    在使用ajax请求的时候 ,如果服务器返回的是500错误,或者其他非正常的http错误状态码时 会提示下面的错误  而我们需要把错误信息处理出来 $.ajax({ type:'get', url:&q ...

  9. python迭代和切片

    from collections import Iterable #切片************************ # #取一个list或tuple的部分元素是非常常见的操作 ,Python提供 ...

  10. 我对asp.net运行机制的理解

    有一本书叫<asp.net 本质论>,作者名叫冠军.我看了几次,都没有坚持看下来.这次连续看完了前三章,然后参考网上的资料,总结下我对.net运行机制的理解. 先上两张图: 看着这两张图, ...