我正试图围绕ES6中Classes的语法。同时通过Bonnie Eisenman的Learning React Native学习Fabric本土。
当回调是一个Class“方法”时,我遇到了一个关于在回调中访问this
的问题。我知道在StackOverflow上已经多次提出了回调中词法this
的问题。例如在
How to access the correct `this` context inside a callback?
根据我的在线研究,我遇到了一个解决方案。但我不确定这是在ES6中这样做的正确方法。
当我尝试以下内容时,我的问题出现了:
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: ''
};
}
_handleTextChange(event) {
console.log(event.nativeEvent.text);
this.setState({zip: event.nativeEvent.text})
}
render() {
return (
<TextInput
style={styles.input}
onSubmitEditing={this._handleTextChange}/>
);
}
}
(我只是对本书中的示例进行了略微修改,以匹配ES6类语法和导入/导出语法而不是Require。)
如果我这样做,this
中的_handleTextChange
未定义(无法读取未定义的属性'setState')。我对此感到惊讶。来自其他OO语言,我正在解释,好像这个方法表现得更像是一个静态方法。
我已经能够通过跳过类方法并使用箭头符号来解决这个问题。 onSubmitEditing={event => this.setState({name: event.nativeEvent.text})}
。哪个工作正常。我没有遇到任何问题或困惑。
我真的想弄清楚如何调用类方法。经过一番研究后,我通过以下方式成功实现了这项工作:onSubmitEditing={this._handleTextChange.bind(this)}
。也许我误解了JavaScript的一个基本方面(我是JS的初学者),但这对我来说似乎完全是疯了。是否真的无法从方法中访问对象的上下文而没有将对象显式绑定到...它自己的方法,在它被调用的位置?
我还尝试在构造函数中添加var self = this;
并在self.setState
中调用_handleTextChange
。但是,发现它不起作用并不是太惊讶。
当一个对象被称为回调时,从一个方法中访问对象的正确方法是什么?
答案 0 :(得分:14)
React.createClass(ES5)创建类的方法有一个内置功能,可以自动将所有方法绑定到this
。但是在ES6中引入classes
并迁移React.createClass时,他们发现对于那些在其他类中不习惯此功能的JavaScript开发人员来说可能有点混乱,或者当他们从React迁移到其他类时可能会感到困惑。类。
所以,他们决定不把这个内置到React的类模型中。如果你想要
,你仍然可以在构造函数中显式预绑定方法class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: ''
};
this._handleTextChange = this._handleTextChange.bind(this); //Binding to `this`
}
_handleTextChange(event) {
console.log(event.nativeEvent.text);
this.setState({zip: event.nativeEvent.text})
}
但我们总是有一种简单的方法来避免这种预先绑定。是啊!你说对了。箭头功能。
class WeatherProject extends Component {
constructor(props) {
super(props);
this.state = {
zip: ''
};
}
_handleTextChange = event => {
console.log(event.nativeEvent.text);
this.setState({zip: event.nativeEvent.text})
}
render() {
return (
<TextInput
style={styles.input}
onSubmitEditing={this._handleTextChange}/>
);
}
}
BTW,这都是关于React的。 ES6类总是有一种方法可以从方法中访问对象的上下文,而无需将对象显式绑定到它自己的方法上。
class bindTesting {
constructor() {
this.demo = 'Check 1';
}
someMethod() {
console.log(this.demo);
}
callMe() {
this.someMethod();
}
}
let x = new bindTesting();
x.callMe(); //Prints 'Check 1';
但这并不打印&#39; Check 1&#39;如果我们在JSX Expression中调用它。
编辑::正如@Oka所提到的,类体中的箭头函数是ES7 +特性,可在编译器/ polyfill中使用,例如babel。如果您不使用支持此功能的转发器,我们可以如上所述绑定到this
或者像这样写一个新的BaseComponent(这是一个坏主意)
class BaseComponent extends React.Component {
_bind(...methods) {
methods.forEach( (method) => this[method] = this[method].bind(this) );
}
}
class ExampleComponent extends BaseComponent {
constructor() {
super();
this._bind('_handleTextChange', '_handleClick');
}
// ...
}
答案 1 :(得分:6)
在常规的旧JavaScript中突破ES6和React一段时间,当你传递一个对象的方法时,它只是对函数本身的引用,而不是对象和的函数。
任何调用函数都可以通过正常调用函数来选择使用隐式this
,或者甚至可以选择使用.call
和.apply
或{{1来更改上下文}}
.bind
正在发生的事情是,您将var O = {
foo: function () {
console.log(this);
},
bar: 51
};
O.foo(); // `this` is O, the implicit context, inferred from the object host
var foo = O.foo;
foo(); // `this` is is the global object, or undefined in Strict Mode
函数传递给事件发射器,该事件发射器将在稍后执行。事件发射器不知道它作为方法接收了该函数。它只是执行它。
_handleTextChange
看看上下文共享:
var O = {
foo: function (event) {
console.log(this);
console.log(event);
},
bar: 51
};
function invoke (func) { // the function reference held by O.foo is now held by `func`
func('some param'); // it has no idea as to what the contextual `this` is bound to, maybe its implicitly global, maybe its explicitly bound, maybe its undefined
}
invoke(O.foo);
invoke(O.foo.bind(O)); // A copy of the function with the context explicitly bound
你可以通过这些例子随意复杂化。
答案 2 :(得分:3)
也许我误解了JavaScript的一个基本方面(我是JS的初学者),但这对我来说似乎完全是疯了。是否真的无法从方法中访问对象的上下文而没有将对象显式绑定到...它自己的方法,在它被调用的位置?
嗯,“方法”不是由javascript中的对象拥有。所有函数都是一等值(对象),而不是对象或类的“部分”。
调用函数时会发生this
value的绑定,具体取决于函数的调用方式。使用方法表示法的函数调用将this
设置为接收对象,事件侦听器调用将其this
设置为当前事件目标,而普通函数调用仅具有undefined
。
如果要访问实例上的方法,它实际上只是标准原型继承属性访问,它产生一个函数,然后调用该函数并动态绑定到接收器。
如果要在函数作为事件侦听器时将函数作为方法调用,则需要显式创建执行此操作的函数 - “绑定”方法。在ES6中,箭头符号通常是首选。