Javascript中6种this绑定方法

对于大多数开发者来说,JavaScript 的 this 关键字会造成诸多困扰。由于 JavaScript 不具备如 Java 等语言的严格类模型,因而除非是在处理回调,否则代码中的 this 指向并不清晰。

一般来说,对于部分运行中的代码(非回调)会通过 new 关键字和 Function.prototype 提供的一些方法,如 call/apply 等来绑定函数的上下文。

问题

在每个 class 中,React 使用 this 指向组件本身,这会给开发者造成一些困扰。如在 React 组件中,可能会经常看到类似如下的代码:

this.setState({ loading: true });

fetch('/').then(function loaded() {
  this.setState({ loading: false });
});
上述代码会造成 TypeError ,因为 this.setState 不是一个函数。抛出 TypeError 的原因是当 promise 的回调被调用时,内部的上下文已经改变了,this 指向了错误的对象。

那么,怎么正确绑定代码中的 this 呢?

选择

本文提供的 6 种方式中,有一些是比较老的技术,另一些是针对 React 的,还有一些可能浏览器也不支持,但还是值得探讨一下。

1、this 别名
这种方式就是在 React 组件的作用域顶端创建一个指向 this 的变量:

var component = this;
component.setState({ loading: true });

fetch('/').then(function loaded() {
  component.setState({ loading: false });
});
这种方式方便,易于理解,并能保证 this 会指向正确的上下文。

2、.bind(this)
这种方式是在函数运行时将 this 注入到回调中,使回调中的 this 能指向正确的上下文:

this.setState({ loading: true });

fetch('/').then(function loaded() {
  this.setState({ loading: false });
}.bind(this));
在 JavaScript 中,所有函数都有 bind 方法,其允许你为 this 指定特定值。一旦函数被绑定,上下文就不能被覆盖,也就意味着 this 会指向正确的上下文。

3、React Component Methods
当使用 React.createClass 来定义组件时,React 允许你随意在此组件的类中定义方法,而在方法中调用的 this 会自动绑定到组件自身:

React.createClass({
  componentWillMount: function() {
    this.setState({ loading: true });

    fetch('/').then(this.loaded);
  },
  loaded: function loaded() {
    this.setState({ loading: false });
  }
});
对于不是非常复杂的组件来说,这是一种非常不错的解决 this 指向问题的方式。而事实上呢,如果在组件的方法中使用 .bind(this),React 会抛出一个警告:

bind(): You are binding a component method to the component. React does this for you automatically in a high-performance way, so you can safely remove this call.
但对于 ES2015 的类 来说,自动绑定并不适用。

4、箭头函数
ES2015 规范引入了箭头函数,使函数的定义更加简洁。箭头函数会隐式返回一个值,但更重要的是,它是在一个封闭的作用域中使用 this:

this.setState({ loading: true });

fetch('/').then(() => {
  this.setState({ loading: false });
});
不管嵌套多少层,箭头函数中的 this 总能指向正确的上下文,因为函数体内的 this 指向的对象,就是定义时所在的对象,而不是使用时所在的对象。但缺点就是,由于箭头函数不能命名,因而在调试时,堆栈信息给的标签是 anonymous function。

如果你用 Babel 将 ES6 的代码转换成 ES5 的代码,就会发现两个有趣的现象:

在某些情况下,编译器能判断函数名是否被赋值给了某个变量
编译器使用 别名 来维护上下文
const loaded = () => {
  this.setState({ loading: false });
};

// will be compiled to

var _this = this;
var loaded = function loaded() {
  _this.setState({ loading: false });
};
5、ES7 的绑定语法
在 ES7 中,有一个关于 bind 语法 的提议,提议将 :: 作为一个新的绑定操作符,该操作符会将左值和右值(一个函数)进行绑定。

以 map 的实现为例:

function map(f) {
  var mapped = new Array(this.length);

  for(var i = 0; i < this.length; i++) {
    mapped[i] = f(this[i], i); 
  }

  return mapped;
}
与 lodash 不同,我们不需要传递数据给 map 作为参数:

[1, 2, 3]::map(x => x * 2)
// [2, 4, 6]
对下面的代码熟悉吗?

[].map.call(someNodeList, myFn);
// or
Array.from(someNodeList).map(myFn);
ES7 的绑定语法允许你像使用箭头函数一样使用 map:

someNodeList::map(myFn);
在 React 中也是可以使用的:

this.setState({ loading: true });

fetch('/').then(this::() => {
  this.setState({ loading: false });
});
6、方法传参指定
一些函数允许为 this 传递一个明确的值,保证其指向正确的上下文,例如 map 函数则将 this 作为最后一个参数:

items.map(function(x) {
  return <a onClick={this.clicked}>x</a>;
}, this);
虽然代码能运行,但这不是函数的一致实现。大部分函数并不接受 this 参数,所以最好还是采用上文中的其它方式来绑定 this 。

时间: 2024-10-16 04:54:58

Javascript中6种this绑定方法的相关文章

JavaScript中5种调用函数的方法

 这篇文章主要介绍了JavaScript中5种调用函数的方法,本文详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助,需要的朋友可以参考下     这篇文章详细的介绍了Javascript中各种函数调用的方法及其原理,对于理解JavaScript的函数有很大的帮助! JavaScript,调用函数的5种方法 一次又一次的,我发现,那些有bug的Javascript代码是由于没有真正理解Javascript函数是如何工作而导致的(顺便说一下

javascript 前端-javascript中文本输入框通过bind方法绑定得到焦点和失去焦点时间

问题描述 javascript中文本输入框通过bind方法绑定得到焦点和失去焦点时间 通过id找到文本输入框,将该文本输入框在JavaScript中通过bind方法绑定得到焦点和失去焦点事件,不要在html中实现! 解决方案 $("input[@type=text]").bind({"focus":function(){alert(new Date())},"blur":function(){alert(new Date()}}) 解决方案二:

JavaScript中的this关键字使用方法总结

 这篇文章主要介绍了JavaScript中的this关键字使用方法总结,本文讲解了作为对象方法调用.作为函数调用.作为构造函数调用.使用 apply 或 call 调用等内容,需要的朋友可以参考下     在javascritp中,不一定只有对象方法的上下文中才有this, 全局函数调用和其他的几种不同的上下文中也有this指代. 它可以是全局对象.当前对象或者任意对象,这完全取决于函数的调用方式.JavaScript 中函数的调用有以下几种方式:作为对象方法调用,作为函数调用,作为构造函数调用

js中this绑定问题-javascript中关于this的绑定问题

问题描述 javascript中关于this的绑定问题 var point = { x : 0, y : 0, moveTo : function(x, y) { // 内部函数 var moveX = function(x) { this.x = x;//this 绑定到了哪里? }; // 内部函数 var moveY = function(y) { this.y = y;//this 绑定到了哪里? }; moveX(x); moveY(y); } }; point.moveTo(1, 1

JavaScript中消除闭包的一般方法介绍

 这篇文章主要介绍了JavaScript中消除闭包的一般方法介绍,本文直接给出了操作示例,需要的朋友可以参考下     JavaScript 的闭包是一个其主动发展的特性, 也是一个被动发展的特性. 也就是说, 一方面, JS 有了闭包能更好解决一些问题. 另一方面, JS 为了解决某些问题, 而不得不使用闭包勉强来解决问题. 前者这里不讨论, 如果 JS 闭包能更好的解决问题, 当然使用闭包更好. 我讨论的是后者, 是因为 JS 本身的限制, 而不得不磕磕绊绊地用闭包来解决的问题, 例如"变量

javascript中数组和字符串的方法对比_javascript技巧

前面的话 字符串和数组有很多的相同之处,它们的方法众多,且相似度很高:但它们又有不同之处,字符串是不可变值,于是可以把其看作只读的数组.本文将对字符串和数组的类似方法进行比较 可索引 ECMAScript5定义了一种访问字符的方法,使用方括号加数字索引来访问字符串中的特定字符 可索引的字符串的最大的好处就是简单,用方括号代替了charAt()调用,这样更加简洁.可读并且可能更高效.不仅如此,字符串的行为类似于数组的事实使得通用的数组方法可以应用到字符串上 如果参数超出范围或是NaN时,则输出un

深入理解JavaScript中为什么string可以拥有方法_javascript技巧

引子 我们都知道,JavaScript数据类型分两大类,基本类型(或者称原始类型)和引用类型. 基本类型的值是保存在栈内存中的简单数据段,它们是按值访问的.JS中有五种基本类型:Undefined.Null.Boolean.Number和String. 引用类型的值是保存在堆内存中的对象,它的值是按引用访问的.引用类型主要有Object.Array.Function.RegExp.Date. 对象是拥有属性和方法的,所以我们看到下面这段代码一点也不奇怪. var favs=['鸡蛋','莲蓬']

注意JavaScript中RegExp对象的test方法

javascript|对象 javascript 中的 RegExp 对象用于正则表达式相关的操作,这个对象提供了一个方法 test 来判定某个字符串是否满足某个 pattern. 返回值是 true/false.今天我碰到了一个问题: <script type="text/javascript"><!--var re = /^\d+(?:\.\d)?$/ig;    alert(re.test('112.3'));alert(re.test('33'));//--&

ASP中五种连接数据库的方法

连接数据库 ASP中五种连接数据库的方法 简介 介绍ASP连接sql,连接access,等数据库的方法! 正文 ASP中五种连接数据库的方法 第一种 - 这种方法用在ACCESS中最多 strconn = "DRIVER=Microsoft Access Driver (*.mdb);DBQ=" & Server.MapPath("aspfree.mdb") set conn = server.createobject("adodb.connect