this 指向问题
JavaScript 的 this 原理 参考:http://www.ruanyifeng.com/blog/2018/06/javascript-this.html 或
https://juejin.cn/post/7144332319279546404?share_token=6df617ba-1243-416d-a5c7-c7ad8b797035
this 指向
- 全局作用域下的this指向window
- 如果给元素的事件行为绑定函数,那么函数中的this指向当前被绑定的那个元素
- 函数中的this,要看函数执行前有没有
.。
有.
的话,点前面是谁,this就指向谁,如果没有点,指向window
- 自执行函数中的this永远指向window
- 定时器中函数的this指向window
- 构造函数中的this指向当前的实例
- call、apply、bind可以改变函数的this指向
- 箭头函数中没有this,如果输出this,就会输出箭头函数定义时所在的作用域中的this。
注意:箭头函数 中 的 this,有可能是需要运行时才能决定。https://www.jianshu.com/p/985a0ee0bbd7
箭头函数中的this 虽然是 定义时 所在的 作用域的this,但是 如果 this 定义时所在的作用域 的 this 是运行时改变决定,则 箭头函数的 this 也就同样 需要运行时决定。function foo(){ setTimeout(() => { console.log("id:", this.id) }, 100); } foo.call({ id:42 });
如上,箭头函数所在 作用域 this 是可以改变的。那么对应 箭头函数 的this 也会改变。
总结:
-
- 一个对象是不会产生新的作用域的,所以对象下属性直接使用this,这个this是对象外的作用域下的this。如下
var catName = "ketty" var obj = { catName: "obj 的 ketty", newCat: this.catName // ketty,这里的 this就是obj外面环境的this,obj不是函数 本身 无法产生 作用域,也就不会改变this的值。 }
这点理解在 vue 中是很重要的,因为vue中常用this指向当前组件实例。没理解透,容易出错。
- 能产生作用域的环境,才有可能内部隐式创建新的this;产生新作用域环境的,不一定会隐式创建this变量,如 箭头函数。
- 一个对象是不会产生新的作用域的,所以对象下属性直接使用this,这个this是对象外的作用域下的this。如下
闭包函数(返回函数内)的this指向外围作用域的this(一般是Windows,当然bind等可以改变外网环境的this)
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); //the Window。 因为返回的闭包函数,再执行时 就变成一个普通函数的执行了。所以this 就是window
以下除了匿名函数
1、对象调用函数的时候,函数里面会有一个隐式的赋值操作 var this = 调用的对象 (没有调用对象,即执行函数 fun(),其实就是window调用,结果还是window),其它的如何情况都不会存在隐式的操作 this 的值。
//对象方法调用 var person = { run: function () {console.log(this)} } person.run() // person
https://blog.csdn.net/qq_33988065/article/details/68957806
2、(这个太平常了,不用特别去套理论,构造函数就是这样用的)new一个对象时,同样可以看做是对象调用构造函数(事实上构造函数确实执行了),构造函数里面隐式的执行了 var this = 调用的对象 。
3、对象调用函数的时候,函数内才会出现 this改变的情况,即隐式的出现 var this = 调用的对象。其它情况 this 都不操作,里面的this 都是作用域链上游的 this值;
函数调用函数,不会出现var this重新赋值的情况,如下面的多层函数调用。只有第一个函数是window对象调用 fun()函数,fun函数先进行隐式操作 var this = window,
fun() 里面的函数没有对象调用,只是函数调用函数(执行函数),所以fun2函数的 this 根据作用域链就近原则,最近的this,就是fun函数里面的this = window。
function fun2() { console.log(this); } function fun1(fun2) { fun2(); } function fun(fun1) { fun1(fun2); } fun(fun1);
this的指向在 调用(即运行) 的时候确定,全局下的函数中的this不一定指向的是window,看谁在调用它。所以所以引起混淆。(这点和变量的作用域,变量的作用域是 声明的时候确定的,而不是运行时)
如:下面init函数没有人调用,通过赋值,把init函数赋值给了obj.fun函数,最后是obj在调用fun函数,init函数并没有直接执行。
function init() { console.log(this.name); } function test(){ var obj= {}; obj.name = "中国" obj.fun = window.init; obj.fun(); } test(); // 中国 // 这里this指向obj
感悟:vue.js中出现这种情况,分析出上面的这种的this指向。所以在实际项目中框架(或库、插件)中的参数调用外部的函数,外部函数千万不要带this,
因为我们不知道框架内是怎么实现的,这个this被指向哪个对象了。如果内部的this指向很明确就没关系了,如
下面的this很明确的指向obj2,init 函数到了其它函数里面,不管怎么变,init内的结构不会变,this指向就不会改变。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
function init() { var obj2 = { name : "小李", fun2 : function () { console.log(this.name); } } obj2.fun2(); }
总结(个人): this指向问题可以把他看做是一个变量,利用js作用域链就可以很好确定 this指向谁了。
箭头函数的this指向
1、剪头函数this的指向是定义时this的指向,而不是调用时this的指向。(这个和 es5 的this指向是不一样的)
手动绑定 this 的指向:https://www.jianshu.com/p/87e3f586f35f
1、this 都是在函数内出现(全局上不需要this,就是window),函数本身就是一个对象。所有的函数的原型上都有,绑定this的方法。
a、call, apply (是改变this指向,立即执行的。)
b、bind (返回了一个新的函数,这是创建了一个新函数,并没有改变原来的函数)
总结:可以这样理解,call, apply绑定的函数,在执行时,先执行了 this = 绑定的object。而 bind 函数是创建了一个新的函数,这个新的函数第一行就是 this = 绑定的object。两者都不会导致原函数的变化。
碰到的不合理问题:
- 自定义检验规则 箭头函数 中使用的this指向了第一个参数?https://www.jianshu.com/p/148f3f324a17(这里用的是普通函数,是可能的)
情景:在杭州银行虚拟机中开发,使用 ant-design-vue 的 from 表单的自定义 校验,用的是 箭头函数。箭头函数 里面的 this 按理来说 应该是 vue组件对象,但 实际上却是 第一个参数 rule 对象。简化 如下代码export default { data() { let validatePass2 = (rule, value, callback) => { console.log(this) callback(); }; return { rules: { checkPass: [{ validator: validatePass2, trigger: 'change' }] } }; },
网上找了很多资料,也没有找到原因。
最后猜测 可能的 结果是:webpack 编译 .vue 文件 后导致的问题,编译后的代码并不是完全符合 源码的逻辑。webpack 编译后就是一个黑盒子,我们不知道具体处理了什么。
可能1:源码中 这个箭头函数 定义的 地方 可能data()里,但是webpack编译后,定义的位置可能发生改变了;
可能2:源码中 箭头函数 可能 被编译成 普通函数(语言降级了)。