上一篇挖了个坑,今天给补上javascript
你是否是也曾像我同样:java
编写了个函数明明能够正常工做,可是一作为事件回调函数就报
undefind
了node在编写React组件时,看到在构造函数中还得对每一个方法bind一下 :数组
this.funOne = this.funOne.bind(this); this.funTwo = this.funTow.bind(this);
多么奇怪的写法,为啥子还要再bind下呢? 不如删了,而后就各类
undefined
了浏览器
要理解为何会undefined
还得从this
提及: app
var name = 'tianlang'; function getName() { console.log(this.name); } getName();
这段代码会输出:less
tianlangide
咱们只需加一行看是不相关的代码,就能让它报undefined
:函数
var name = 'tianlang'; function getName() { 'use strict' console.log(this.name); } getName();
VM412:4 Uncaught TypeError: Cannot read property 'name' of undefined
at getName (<anonymous>:4:22)
at <anonymous>:6:1
getName @ VM412:4
(anonymous) @ VM412:6 this
只因在人群中多看了你一眼,就在代码中多写了行use strict
整个程序都崩溃了。
JavaScript执行引擎看到咱们写了use strict
就启用了严格模式,严格模式下函数getName中的this指向undefind
,在非严格模式下getName中的this指向全局变量(在浏览器运行环境中就是window, 在node运行环境中就是global)。
就这么简单? 这也不神出鬼没啊。 鬼那能容易看到,若是那么容易看到也就不叫鬼了,接着往下面看:
var name = 'tianlang' var person = { name: 'tianlangstudio' } function getName() { console.log(this.name); } person.getName = getName; person.getName(); getName();
你能够猜下,在看执行结果:
tianlangstudio
tianlang
一样是调用getName
为何获取的name
不同呢?
这是由于函数中的this是执行函数调用者的。当咱们使用person.getName
的方式执行时getName
中的this就指向了person.
只有在直接执行函数又没有手动绑定操做(后面会介绍)又在非严格模式下this才指向全局变量.
也就是函数内的this具体执行谁跟调用的方式有关。不信你能够再添加两行代码试下:
var personGetName = person.getName; personGetName();
执行结果是:
tianlang
这就是为何定义的函数明明能够正常执行,可是一作为事件回调函数就报undefind了。
就像这样:
someHtmlDomNode.addEventListener('click', person.getName);
你能够认为person.getName
被赋值给了一个变量personGetName
再事件触发时实际是执行的personGetName()
. 再也不是person.getName
这种样式的了,它变了。
那怎么让它仍是以person.getName
的方式被调用呢?能够再外面包个函数,或者使用手动绑定操做:
someHtmlDomNode.addEventListener('click', funciton() { person.getName() });
someHtmlDomNode.addEventListener('click', person.getName.bind(person));
这就是为何定义React组件时为何还须要对每一个方法再bind次了。bind操做就是手动为函数指定this
。除了bind
还有call
和apply
也能够为函数指定执行时的this
值。不一样的是bind的返回值是一个新的函数,你能够在你乐意的时候再执行这个函数而call
和apply
是绑定和执行一块儿执行的,因此它们接受不仅一个参数。除了跟bind同样须要一个参数做为this
还须要函数运行所须要的参数,这也是apply
和call
不同的地方,一个接受数组做为执行函数的参数,一个是使用任意个参数的形式。
fun.apply(thisObj, ['arg1', 'arg2'])
fun.call(thisObj, 'arg1', 'arg2', 'arg3')
在React组件中写那么多看是无用的bind真的有点辣眼睛,有没有更好的方式解决呢?
能够实用箭头函数注册事件监听或定义方法,就像这个样子:
someHtmlDomNode.addEventListener('click', () => { this.getName() });
class SomeClass { constructor(name) { this.name = name; } getName = () => this.name; } var obj1 = new SomeClass("tianlang"); obj1.getName();// tianlang var objGetName = obj1.getName; objGetName();//tianlang
简单说这是由于:
The best thing is that arrow functions couldn't care less about this! Practically, it means they are totally ignoring it (and maybe hoping this will go away), so the context of this right outside the arrow function stays the same inside it
哇! 该煮饭了,拜拜!