code review时,发现自己在jsx种绑定onClick函数有过这种写法:
// 第一种
class Movie extends React.Component{
constructor(props) {
super(props)
this.state = {
name: 'yuly'
}
}
handleClick (){
console.log(this) // Movie
}
render() {
const { name } = this.state
return (
<div>
<p>this is movie Component --- {name}</p>
<button onClick={()=> this.handleClick()}>click me</button>
</div>
)
}
}
这是不推荐的,因为在每次渲染Movie,render函数执行都会重新创建匿名回调函数。 下面这第二种写法,虽然不会在每次render执行时创建匿名函数,但是在 JavaScript 中,class 的方法默认不会绑定 this。所以调用这个函数的时候, handleClick内部输出 this 的值为 undefined。
// 第二种
<button onClick={this.handleClick>click me</button> //点击 控制台输出undefined
this的指向当前调用栈的第二层(从栈底开始数),在第一种写法中,由于是在箭头函数中调用handleClick,handleClick的调用栈为:匿名箭头函数 -> handleClick,handleClick调用时this的调用位置在箭头函数,而箭头函数会继承外层函数调用的this绑定,所以这时handleClick函数执行this输出Movie。
所以在他人代码中还会看见第三种写法:
// 第三种
class Movie extends React.Component{
constructor(props) {
super(props)
this.state = {
name: 'yuly'
}
}
handleClick (){
console.log(this) // Movie
}
render() {
const { name } = this.state
return (
<div>
<p>this is movie Component --- {name}</p>
<button onClick={this.handleClick.bind(this)}>click me</button>
</div>
)
}
}
其实这种写法从弊端上来讲与第一种写法殊途同归; MDN提供的一种bind(..)实现:
if(!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if(typeof this !== 'function'){
throw new TypeError(
'Function.prototype.bind - what is tring' +
'to be bound is not callable'
);
}
var aArgs = Array.prototype.slice.call( arguments, 1),
fToBind = this,
fNOP = function(){},
fBound = function() {
return fToBind.apply(
(
this instanceof fNOP &&
oThis ? this : oThis
),
aArgs.concat(
Array.prototype.slice.call(arguments)
)
)
}
fNOP.prototype = this.prototype
fBound.prototype = new fNOP() // 创建了一个新函数实例对象
return fBound;
}
}
我们可以看出在bind内部同样创建了一个新的函数。 正确写法是第四种,将handleClick用箭头函数定义,因此 this是 定义时上下文的this -> Movie:
// 第四种
class Movie extends React.Component{
constructor(props) {
super(props)
this.state = {
name: 'yuly'
}
}
handleClick = () =>{
console.log(this) // Movie
}
render() {
const { name } = this.state
return (
<div>
<p>this is movie Component --- {name}</p>
<button onClick={this.handleClick}>click me</button>
</div>
)
}
}
如果需要向handleClick函数传递参数呢?官方推荐写法:
// 传递参数
class Movie extends React.Component{
constructor(props) {
super(props)
this.state = {
name: 'yuly'
}
}
handleClick (e, id) {
console.log(this) // Movie
console.log(e, id)
}
render() {
const { name } = this.state
return (
<div>
<p>this is movie Component --- {name}</p>
<button onClick={(e) => this.handleClick(e,id)}>click me</button>
// 或者
// </div><button onClick={this.deleteRow.bind(this, id)}>click me</button>
)
}
}
欢迎指正