JavaScript中的this
2016-07-04 11:02
645 查看
什么是this
那么问题来了
如何使this确定
bind
Fat Arrow
鸣谢
最近在学习ReactNative,免不了被坑在JS上,跟Java和Objective-C不同,JS方法里的this显得很另类,有点令人困惑。
什么是
要说清this是什么,可以从
其中
JavaScript里的其他方法调用方式大致可以看做这个调用的语法糖[^Call]。
在ES5前,function里的this默认会是window或者global对象,而使用了严格模式的ES5,全局function里的this将会是
对于一个方法来说
通常我们把
细心的盆友看出来了,我这样写是不行的,ListView的renderRow方法是由react执行的,它调用
JavaScript中
如何使
在ES5之前,人们通过一个简单方法帮助改正错误的this:
尽管我们可以在任何地方调用
这个方法最终被ES5引入的
所以,前文里面困扰了我的ReactNative问题,解决方法也许是:
而考虑到ReactNative,
另外
不过在Babel的实现中说明了这个语法是
这种方法的缺点是参数个数是固化的,如果想处理原方法的更多参数,需要在这里显式写出这些参数,不太灵活。
what’s ‘this’
jsx中不推荐使用bind和箭头函数
mozilla bind文档
谢谢收看
那么问题来了
如何使this确定
bind
Fat Arrow
鸣谢
最近在学习ReactNative,免不了被坑在JS上,跟Java和Objective-C不同,JS方法里的this显得很另类,有点令人困惑。
什么是this
要说清this是什么,可以从Function.prototype.call()方法说起,这个方法近似于function调用的原始实现,它的方法签名是这样的:
fun.call(thisArg[, arg1[, arg2[, ...]]])
其中
thisArg代表的就是方法里的
this,而其他参数,则是
arg1、
arg2以可变长度参数的形式传递。调用的过程和结果如下:
function hello(thing) { console.log(this + " says hello " + thing); } hello.call("Yehuda", "world") //=> Yehuda says hello world
JavaScript里的其他方法调用方式大致可以看做这个调用的语法糖[^Call]。
在ES5前,function里的this默认会是window或者global对象,而使用了严格模式的ES5,全局function里的this将会是
undefined:
// this: hello("world") // desugars to: hello.call(undefined, "world");
对于一个方法来说
this并不是一成不变,具体是什么取决于调用这个方法的时机:
function hello(thing) { console.log(this + " says hello " + thing); } person = { name: "Brendan Eich" } person.hello = hello; person.hello("world") // still desugars to person.hello.call(person, "world") hello("world") // "[object DOMWindow]world" //具体环境决定
通常我们把
this形容为
上下文就是因为这个。
那么问题来了
JavaScript中,我们经常要将方法传递给其他方法,当做回调函数,比如最近学习的ReactNative,JSX中经常要将方法作为参数传递:render() { return ( <ListView dataSource={this.props.dataSource} renderRow={this._renderRow} /> ) } ... _renderRow(itemData) { return ( <TouchableHighlight onPress={this._rowPressed} > ...not important </TouchableHighlight> ) } _rowPressed() { ...not important }
细心的盆友看出来了,我这样写是不行的,ListView的renderRow方法是由react执行的,它调用
_renderRow的时候,上下文
this必然不是声明render方法所在的实例,
_renderRow方法里的
this._rowPressed必然是
undefined。
JavaScript中
Function是一等类型,可以被显式传递,所以必然会出现上下文不对的问题,在没有深入研究过的开发者手中,往往忽视这个问题,写出大坑。
如何使this
确定
bind
这个问题也困扰了JS开发者很久,如何解决呢?在ES5之前,人们通过一个简单方法帮助改正错误的this:
var person = { name: "Brendan Eich", hello: function(thing) { console.log(this.name + " says hello " + thing); } } var boundHello = function(thing) { return person.hello.call(person, thing); } boundHello("world");
尽管我们可以在任何地方调用
boundHello方法,可是
boundHello实际上是对上下文和原始
hello方法进行了封装,所以最终
hello里的
this始终是
person。
这个方法最终被ES5引入的
Function.prototype.bind方法所替代,所以现在我们的代码里可以这样使用:
var boundHello = person.hello.bind(person); boundHello("world") // "Brendan Eich says hello world"
所以,前文里面困扰了我的ReactNative问题,解决方法也许是:
render() { return ( <ListView dataSource={this.props.dataSource} renderRow={this._renderRow.bind(this)} /> ) } ... _renderRow(itemData) { return ( <TouchableHighlight onPress={this._rowPressed.bind(this)} > ...not important </TouchableHighlight> ) } _rowPressed() { ...not important }
而考虑到ReactNative,
render方法的性能要求,不能在
render过程中创建新方法,所以最终解决方案是这样的:
constructor() { super() this._renderRow = this._renderRow.bind(this) this._rowPressed = this._rowPressed.bind(this) } render() { return ( <ListView dataSource={this.props.dataSource} renderRow={this._renderRow} /> ) } ... _renderRow(itemData) { return ( <TouchableHighlight onPress={this._rowPressed} > ...not important </TouchableHighlight> ) } _rowPressed() { ...not important }
另外
bind(this)在ES6里还有新语法糖:
this._renderRow = ::this._renderRow this._rowPressed = ::this._rowPressed
不过在Babel的实现中说明了这个语法是
highly experimental的,所以最后用不用,follow your heart~
Fat Arrow
ES6引入了箭头匿名方法,它的方法体里的this是会绑定给初始化它的实例的,所以constructor里的方法也可以改为:
this._renderRow = (rowData) => this._renderRow(rowData) this._rowPressed = () => this._rowPressed()
这种方法的缺点是参数个数是固化的,如果想处理原方法的更多参数,需要在这里显式写出这些参数,不太灵活。
鸣谢
bind新语法what’s ‘this’
jsx中不推荐使用bind和箭头函数
mozilla bind文档
谢谢收看
杏树林研发 王儒林
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- 最后一次说说闭包
- Ajax
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法
- Redux系列02:一个炒鸡简单的react+redux例子
- JavaScript 各种遍历方式详解
- call/apply/bind 的理解与实例分享