call apply bind.md
> call、apply、bind的作用是改变函数运行时的this指向
## 关于this对象
this对象在运行时基于函数的执行环境绑定的,在非严格模式的全局环境中,this指向window,而当函数被作为某个对象的方法调用时,this等于那个对象,不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window(严格模式下,在全局环境中,this指向undefined)。
## 异同
- call, apply, bind 第一个参数是要绑定给this的值,区别是传递的参数不同,call, bind后面传入的是一个参数列表,apply后面传入的是一个包含多个参数的数组 在非严格模式中当第一个参数为null,undefined的时候,默认指向window,严格模式下,默认指向undefined。
```js
var person = {
name: "tjj",
age: 23
};
function say(job, hobby){
console.log(this.name + ":" + this.age+ ":" + job + ":" + hobby);
}
say.call(person, "Teacher", "Swimming"); // tjj:25:Teacher:Swimming
say.apply(person, ["Teacher", "Swimming"]); // tjj:25:Teacher:Swimming
var sayPerson = say.bind(person, "Teacher", "Swimming");
sayPerson(); // tjj:25:Teacher:Swimming
```
- bind方法与call/apply 最大的不同是前者返回一个绑定上下文的函数,后者则是直接执行了函数
```js
var value = 2;
var foo = {
value: 1
};
function bar(name, age) {
return {
value: this.value,
name: name,
age: age
}
};
bar.call(foo, "Jack", 20); // 直接执行了函数
// {value: 1, name: "Jack", age: 20}
var bindFoo1 = bar.bind(foo, "Jack", 20); // 返回一个函数
bindFoo1();
// {value: 1, name: "Jack", age: 20}
var bindFoo2 = bar.bind(foo, "Jack"); // 返回一个函数,并且预设了第一个参数
bindFoo2(20);
// {value: 1, name: "Jack", age: 20}
bindFoo2(40);
// {value: 1, name: "Jack", age: 40}
```
## call的实现
## 使用场景
```js
var nickname = "Kitty";
function Person(name){
this.nickname = name;
this.distractedGreeting = function() {
setTimeout(function(){
console.log("Hello, my name is " + this.nickname);
}, 500);
}
}
var person = new Person('tjj');
person.distractedGreeting();
//Hello, my name is Kitty
```
这里输出的nickname是全局的,并不是我们创建的person 时传入的参数,因为setTimeout在全局环境中执行,所以this指向的是window(把this换成异步回调也是一样的,比如接口请求回调)
解决办法:
1. 缓存this 值
```js
var nickname = "Kitty";
function Person(name){
this.nickname = name;
this.distractedGreeting = function() {
var self = this;
setTimeout(function(){
console.log("Hello, my name is " + self.nickname);
}, 500);
}
}
var person = new Person('tjj');
person.distractedGreeting();
// Hello, my name is tjj
```
2. 使用 bind
```js
var nickname = "Kitty";
function Person(name){
this.nickname = name;
this.distractedGreeting = function() {
setTimeout(function(){
console.log("Hello, my name is " + this.nickname);
}.bind(this), 500);
}
}
var person = new Person('tjj');
person.distractedGreeting();
// Hello, my name is tjj
```
- 其他用法:
```js
Object.prototype.toString.call(obj) === '[object Array]' // 判断数据类型
Array.prototype.slice.call(arguments) // 类数组转化为数组
Math.max.apply(null, [1, 2, 3]) // 获取数据最大值
Math.min.apply(null, [1, 2, 3]) // 获取数据最小值
[].push.apply([1, 2], [3, 4]) // 数组追加
// 继承
function Person(name,age){
// 这里的this都指向实例
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)
```