Function.prototype.bind = function (context) { if (typeofthis !== "function") { thrownewTypeError("not a function"); } let self = this; let args = [...arguments].slice(1); functionFn() {} Fn.prototype = this.prototype; let bound = function () { let res = [...args, ...arguments]; //bind 传递的参数和函数调用时传递的参数拼接 context = thisinstanceof Fn ? this : context || this; return self.apply(context, res); }; // 原型链 bound.prototype = new Fn(); return bound; };
var name = "Jack"; functionperson(age, job, gender) { console.log(this.name, age, job, gender); } var Yve = { name: "Yvette" }; let result = person.bind(Yve, 22, "enginner")("female");
应用:怎么改变 this 的指向
为什么讲这个模块呢,为了便于我们更加透彻的理解上面所讲述的 this 指向问题,以及更加彻底的理解 JS 函数中重要的三种方法:call、apply、bind 的使用;并且在实际的项目开发中,我们经常会遇到需要改变 this 指向的情况。
我们来看下都有哪些方法:
1. 使用 es6 的箭头函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var name = "dabao"; var obj = { name: "jiaru", func1: function () { console.log(this.name); }, func2: function () { setTimeout(function () { this.func1(); }, 1000); }, };
obj.func2(); // Uncaught TypeError: this.func1 is not a function
这时会报错,因为 setTimeout 里函数的 this 指向 Window,而 Window 对象上是没有 func1 这个函数的。下面我们来修改成箭头函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var name = "dabao"; var obj = { name: "jiaru", func1: function () { console.log(this.name); }, func2: function () { setTimeout(() => { this.func1(); }, 1000); }, };
obj.func2(); // jiaru
这时候,没有报错,因为箭头函数的 this 的值取决于该函数外部非箭头函数的 this 的值,也就是 func2 的 this 的值, 即 obj。
2. 在函数内部使用 _this = this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
var name = "dabao"; var obj = { name: "jiaru", func1: function () { console.log(this.name); }, func2: function () { var _this = this; setTimeout(function () { _this.func1(); }, 1000); }, };
obj.func2(); // jiaru
此时,func2 也能正常运行。在 func2 中,首先设置 var _this = this,这里的 this 是指向 func2 的对象 obj,为了防止在 func2 中的 setTimeout 被 window 调用而导致的在 setTimeout 中的 this 为 window。我们将 this (指向变量 obj) 赋值给一个变量 _this,这样,在 func2 中我们使用 _this 就是指向对象 obj 了。
3. 使用 call、apply、bind
call:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var name = "dabao"; var obj = { name: "jiaru", func1: function () { console.log(this.name); }, func2: function () { setTimeout( function () { this.func1(); }.call(obj), 1000 ); }, };
obj.func2(); // jiaru
apply:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var name = "dabao"; var obj = { name: "jiaru", func1: function () { console.log(this.name); }, func2: function () { setTimeout( function () { this.func1(); }.apply(obj), 1000 ); }, };
obj.func2(); // jiaru
bind:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var name = "dabao"; var obj = { name: "jiaru", func1: function () { console.log(this.name); }, func2: function () { setTimeout( function () { this.func1(); }.bind(obj)(), 1000 ); }, };
obj.func2(); // jiaru
call、apply、bind 都能改变 this 的上下文对象,所以也没有报错,可以正常执行。 具体原因可看上述第七点。