js基础系列之【无奈的痛点-this】
声明:形成本文的出发点仅仅是个人总结记录,避免遗忘,并非详实的教程;文中引用了经过个人加工的其它作者的内容,并非原创。学海无涯
没有过多学院派的解释,先来几个例子和日常用法,至少在我的使用中,这几个例子几乎涵盖了80%的应用场景
(1)一般函数中,this指向全局对象
function foo() { console.log(this); // window }
(2)作为对象方法调用时,this指向调用的对象
function foo() { console.log(this); } var obj = {}; obj.say = foo; obj.say(); // obj
(3)作为构造函数调用时,this指向生成的实例(就是new出来的对象)
var temp; function Foo(name) { this.name = name; temp = this; console.log(this); // {name: 'hello'} } var f = new Foo('hello'); temp === f; // true
(4)apply、call、apply调用函数时,this指向第一个参数(这里可以指定函数调用时this的指向)
var temp = 1; var obj = { temp: 2, say: function() { return this.temp; } } var obj1 = { temp: 3, } // 对象方法调用 obj.say(); // 2 // 参数为空则相当于在全局环境中被调用 obj.say.apply(); // 1 // 指定this指向obj1 obj.say.apply(obj1); // 3
有了这么多的情况,是时候做一些测试和总结了
先声明一些变量和函数备用
var temp; // 用于临时保存this var obj = {}; // 一个备用对象 function Foo() { // 普通函数 temp = this; } var foo = Foo.bind(obj); // bind硬绑定情况 var bar = { // 对象隐式绑定情况 foo: foo, Foo: Foo, };
1、先来测试一下之前我们已经知道的情况
bar.Foo(); bar === temp; // true this指向调用的对象bar var x = new Foo(); x === temp; // true this指向实例 foo(); obj === temp; // true this指向bind绑定的对象
2、当bind和对象隐式绑定同时出现呢?
bar.foo(); temp === bar; // false temp === obj; // true 结果证明bind硬绑定优先级高于对象隐式绑定
3、当对象隐式绑定和new调用同时出现呢?
var x = new bar.Foo(); bar === temp; // false x === temp; // true 结果证明new调用优先级高于对象隐式绑定
4、当bind和new调用同时出现呢?
var y = new foo(); temp === obj; // false temp === y; // true 结果证明new调用优先级高于对象隐式绑定
OK,总结完成。
一些例子
// 多层调用链 function foo() { console.log( this.a ); } var a = 2; var obj1 = { a: 4, foo: foo }; var obj2 = { a: 3, obj1: obj1 }; obj2.obj1.foo(); //?
多层调用链的情况,反正我第一次看到的时候有些懵,测试结果是4,但是怎么解释呢?
无需过多解释,一个一样的例子我们前面刚确认的:
var temp = 1; var obj = { temp: 2, say: function() { return this.temp; } } obj.say(); // 2;
答案当然是2了,其实上面的obj.say() 难道不能写成window.obj.say() 吗?还需要解释不?
再来一个例子:
var value = 1; var foo = { value: 2, bar: function () { return this.value; } } //示例1 console.log(foo.bar()); // 2 //示例2 console.log((foo.bar)()); // 2 //示例3 console.log((foo.bar = foo.bar)()); // 1 //示例4 console.log((false || foo.bar)()); // 1 //示例5 console.log((foo.bar, foo.bar)()); // 1
如果你没有懵逼,那么你真的很理解this了
其实我们从上面的例子或者我们开发使用中似乎可以总结出这样的规律(我们好像非常喜欢规律的东西):this在函数声明中并没有确定(不像作用域),它是动态绑定的,只有在真正调用它的时候才会被确定,而且是谁调用,指向谁
一直觉得语言的学习首要目标是使用,但是有时候为了理解其原理或者应对(应付)面试之类的可能要不得不做一些更深入(奇怪)的理解,再说不还有20%的情况我们会比较懵吗?
如果你对最后一个例子很懵逼(其实我也是),那推荐你去看一下这篇文章,是的,上面那个例子就是出自这里:https://segmentfault.com/a/1190000009048715
个人觉得需要看这篇文章的同学,并不需要去了解规范,因为这样做的收获和付出不成比例,在现阶段来说。
浙公网安备 33010602011771号