前言
我们知道ES6中引入了箭头函数,可以极大避免 this 产生的错误,但是为了一些老代码的维护,最好还是了解一下ES5中 this 的指向和 call、apply、bind 三者的区别。
this 的指向
在 ES5 中,this 的指向始终坚持一个原理:this 永远指向最后调用它的那个对象
例子:
var me = "windowsMe";
function foo() {
var me = "Jack";
console.log(this); // Window
console.log(this.me); // windowsMe
}
foo();
console.log(me) // Window
var name = "myName";
var a = {
name: "Canddy",
bar: function () {
console.log(this.name);
}
}
a.bar(); // Canddy根据“this 永远指向最后调用它的那个对象”原则,我们看最后调用 foo 的地方 foo(),前面没有调用的对象那么就是 window在调用,这就相当于是 window.foo();而最后调用bar的是a,所以this指向a,打印的是对象a的name
使用 apply、call、bind改变this指向
例子:
var cat = {
word: "miaomiao",
color: "gray",
speak : function() {
console.log(this.word)
}
}
var dog = {
word: "wangwang",
color: "white"
}
cat.speak(); // miao
如何用cat的say方法来显示dog的数据呢
call的写法:
cat.say.call(dog);apply的写法:
cat.say.apply(dog);bind的写法:
cat.say.bind(dog)();如果直接写cat.speak.bind(dog)是达不到效果的,看到区别了吗?call和apply都是对函数的直接调用,而bind方法返回的仍然是一个函数,因此后面还需要()来进行执行才可以。
那么call和apply有什么区别呢?改写一下上面的例子。
var cat = {
word: "miaomiao",
color: "gray",
speak : function() {
console.log(this.word + '-' + weight + '-' + height)
}
}
var dog = {
word: "wangwang",
color: "white"
}
cat.speak(); // miao-1kg-0.2m
call的写法:
cat.speak.call(dog, "1kg", "0.2m");apply的写法:
cat.speak.apply(dog, ["1kg", "0.2m"]);bind的写法:
cat.speak.bind(dog, "1kg", "0.2m")();
cat.speak.bind(dog)("1kg", "0.2m");
可以看到,call后面的参数与方法中是一一对应,而apply的第二个参数是一个数组,数组中的元素是和say方法中一一对应,这是两者最大的区别。而bind可以像call那样传参,也可以在调用的时候再进行传参
call/apply/bind的用途
call/apply/bind的核心理念就是借用方法
A对象有个方法,B对象因为某种原因也需要用到同样的方法,借用 A 对象的方法最便捷,借助已实现的方法,改变方法中数据的this指向,减少重复代码,节省内存。
应用案例如下:
- 准确判断数据类型
function is_type(data, type) {
var alltypes = {
"[object Null]": "null",
"[object Undefined]": "undefined",
"[object Object]": "object",
"[object String]": "string",
"[object Number]": "number",
"[object Boolean]": "boolean",
"[object Array]": "array",
"[object Function]": "function",
"[object Arguments]": "arguments"
"[object Date]": "date",
"[object RegExp]": "regExp",
"[object Map]": "map",
"[object Set]": "set",
"[object HTMLDivElement]": "dom",
"[object Window]": "window",
"[object Error]": "error",
};
var name = Object.prototype.toString.call(data);
var typename = typeObj[name] || "unknown";
return typename === type;
}
console.log(
is_type({}, "object"), // true
is_type({}, "array"), // false
);2.通过apply获取数组最值
var num_arr = [1, 2, 12, 0];
const max = Math.max.apply( Math, num_arr ); // 12
const min = Math.min.apply( Math, num_arr ); // 0其它应用场景还有类数组调用数组方法等,抓住方法借用概念就好,这里就不做过多介绍。