Javascript之this-call/apply/bind
2018.02.01
chen7
js相关
 热度
℃
this
this关键字 在js中可谓随处可见,看似简单,但要做到心里有数还是需要来一次的梳理。
无论是否在严格模式下,在全局执行上下文中(在任何函数体外部)this
都指代全局对象;
在函数内部,this
的值取决于函数被调用的方式。
所以this的值不是固定的,它的值不取决于它所在的位置,而在于他所在的function是被怎样调用的。
接下来理解一下函数的几种调用方式和它的this值吧:
1.全局函数调用
这里又有严格模式和非严格模式的区别。
非严格模式下 this的值默认指向全局对象。
1 2 3 4 5 6 7 8 9 10 11 12
| function a(){ this.b=1; alert(this.b); } a();
function a(){ var b='chen'; console.log(this.b); console.log(this); } a();
|
严格模式下 this将保持他进入执行上下文时的值,所以this将默认undefined。
2.作为方法被调用
this指向它的父级(上一级)对象:
1 2 3 4 5 6 7
| var o = { user:"chen", fn:function(){ console.log(this.user); } } o.fn();
|
更复杂一点案例的理解:
1 2 3 4 5 6 7 8 9 10 11 12
| var o = { a:10, b:{ a:12, fn:function(){ console.log(this.a); console.log(this); } } } var j = o.b.fn; j();
|
this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window.
3.作为构造函数调用
所谓构造函数,就是通过这个函数生成一个新对像(object)。这时,this就指这个新对象。
1 2 3 4 5
| function a(){ this.b = "chen"; } var a2 = new a(); console.log(a2.b);
|
通过以上其实我们可以了解到this的作用,就是可以实现动态指向不同的作用域中,动态实现其功能的特点,比如我们写了一个方法需要作用于多个对象中,此时就可以用this在不同环境下对不同的父级赋能。
call/apply/bind
以上我们可以判定this的默认值,那当我们需要更改this指向不等于默认值,绑一个环境去执行呢?
这个时候就需要用到function的三个方法:
这三个函数的存在意义是改变函数执行时的上下文,再具体一点就是改变函数运行时的this指向。
理解了this
关键字之后我们就更容易看懂下面的这写代码,
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function hello(name){ console.log('hello,'+name+'我是'+this.name); } var user={ name:'chen' }
hello.call(user,'qiqi');
hello.apply(user,['chichi']);
hello2=hello.bind(user); hello2('keke');
|
通过上面得例子我们可以对call、apply、bind三个方法进行总结比较了:
- call和apply的使用方法一样,都是将函数的this指向绑定在一个指定的环境对象中,进行传参执行;
- 二者的区别是传参方式的不同,apply是进行数组传参;
- call和apply在绑定的同时就已经进行了函数执行;
- bind分两步操作,第一步操作只进行环境绑定但不执行函数,之后在新的function中进行传参使用;
让我们再看一个例子去理解会更直观(感谢翻译):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| var context = { foo: "bar" };
function returnFoo () { return this.foo; }
returnFoo();
var bound = returnFoo.bind(context);
bound();
returnFoo.call(context); returnFoo.apply(context);
context.returnFoo = returnFoo; context.returnFoo();
[1,2,3].slice(0,1);
var slice = Array.prototype.slice;
slice(0, 1); slice([1,2,3], 0, 1);
slice.call([1,2,3], 0, 1);
slice.apply([1,2,3], [0,1]);
slice = Function.prototype.call.bind(Array.prototype.slice);
slice([1,2,3], 0, 1);
var bind = Function.prototype.call.bind(Function.prototype.bind);
var context = { foo: "bar" }; function returnFoo () { return this.foo; }
var amazing = bind(returnFoo, context); amazing();
|
推荐阅读
[译] JavaScript 中至关重要的 Apply, Call 和 Bind
深入浅出妙用 Javascript 中 apply、call、bind