this和call/apply/bind
概括的说,call、apply、bind的用途是指定函数调用时所引用上下文对象(context object)的值,即this的值。
深入理解this
普通函数的this
在最普通的函数调用中,this引用的是把函数当成方法调用的上下文对象,此时this值就是window。或者说,在网页的全局上下文中调用函数时,this指向window。
举例:
| var hero = 'Jackie Chan';
let person = { hero:'Eason Chan' };
function myHero(){ return this.hero; }
myHero();
person.myHero = myHero; person.myHero();
|
定义在全局上下文中的函数 myHero()引用了 this 对象。这个 this 到底引用哪个对象必须到
函数被调用时才能确定。
若想只调用myHero()就得到person.hero值,则可以使用call设定this指向:
| myhero(); myHero.call(person,);
myHero.call(null,); myHero.call(undefined,); myHero.call('',); ... myHero.call([其他falsy值],);
|
浏览器里有一条规则:如果传的 context 是 null 或 undefined(不包括其他falsy值),那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined),因此会出现第三行代码以后的结果。
箭头函数的this
| var hero = 'Jackie Chan';
let person = { hero:'Eason Chan' };
let myHero = () => this.hero;
myHero();
person.myHero = myHero; person.myHero();
|
在箭头函数中,this 引用的是定义箭头函数的上下文。 由于箭头函数myHero是在全局作用域中定义的,所以this指向的都是window。
注意:箭头函数的this是固定的,不能被call/apply/bind修改。
闭包中的this
| var color = 'red';
let obj = { color: 'blue', sayColor() { return function color(){ return this.color; } } };
obj.sayColor()();
|
以上代码中,全局变量color和函数color()构成闭包。
具体解释:见《闭包》
要想使obj.sayColor()();返回obj的blue,则应该让obj.color和函数color()构成闭包。可将this保存到闭包可以访问的另一个变量that中:
| var color = 'red';
let obj = { color: 'blue', sayColor() { let that = this; return function color(){ return that.color; } } };
obj.sayColor()();
|
回调函数中的this
回调函数中的this指向window。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var hero = 'Jackie Chan'; function peoplesHero(fn){ fn(); return hero; }
function myHero(){ var hero = 'Eason Chan'; return hero; }
peoplesHero(myHero);
var hero = 'Jackie Chan'; function peoplesHero(){ (function myHero(){ var hero = 'Eason Chan'; return hero; })(); return hero; }
peoplesHero();
|
call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
| function.call(thisArg, arg1, arg2, ...)
|
代码举例在普通函数的this小节已经介绍,不再赘述。
注意:正确的函数调用方式是使用call/apply/bind指定this.
apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。
| function.apply(thisArg, [argsArray])
|
注意:call()方法的作用和 apply() 方法非常非常类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
| function.bind(thisArg[, arg1[, arg2[, ...]]])
|
举例:
| var hero = 'Jackie Chan';
let person = { hero:'Eason Chan' };
function myHero(){ return this.hero; }
var sayHero = myHero.bind(person); console.log(sayHero);
myHero(); sayHero();
|
call/apply/bind的应用场景
参考:call、apply和bind方法的用法以及区别 - 简书
| var arr = [1,2,3,89,46] var max = Math.max.apply(null,arr) var min = Math.min.apply(null,arr)
|
| var trueArr = Array.prototype.slice.call(arrayLike)
|
| var arr1 = [1,2,3]; var arr2 = [4,5,6]; var total = [].push.apply(arr1, arr2);
|
| function isArray(obj){ return Object.prototype.toString.call(obj) == '[object Array]'; } isArray([]) isArray('dot')
|
| function Person(name,age){ this.name = name this.age = age this.sayAge = function(){ console.log(this.age) } } function Female(){ Person.apply(this,arguments) } var dot = new Female('Dot',2)
|
| function log(){ console.log.apply(console, arguments); }
|