在整理Javascript中改变函数内部this指向的方法之前,先介绍一下不同函数的调用方式以及函数内this的指向。
- <script>
- // 函数的调用方式
-
- // 1. 普通函数
- function fn() {
- console.log('人生的巅峰');
- }
- // 调用函数
- // fn(); fn.call();
-
- // 2. 对象的方法
- var o = {
- sayHi: function() {
- cconsole.log('人生的巅峰');
- }
- }
-
- // 调用函数
- o.sayHi();
-
- // 3. 构造函数
- function Star() {};
- // 调用函数
- new Star();
-
- // 4. 绑定事件函数
- btn.onclick = function() {}; // 点击了按钮就可以调用这个函数
-
- // 5. 定时器函数
- setInterval(function() {}, 2000); // 这个函数是定时器自动2秒钟调用一次
-
- // 6. 立即执行函数
- //第一种写法
- (function() {
- console.log('人生的巅峰');
- })();
-
- //第二种写法
- (function() {
- cconsole.log('人生的巅峰');
- }());
-
- // 立即执行函数是自动调用
- script>

bind(), call(), apply()三种方法。call()方法可以立即调用一个函数,并可以改变该函数的this指向。
使用方法: fun.call(thisArg,arg1,arg2,…)
因此当我们想改变 this 指向,同时想调用这个函数的时候,可以使用 call,比如继承。
-
- // 改变函数内this指向 js提供了三种方法 call() apply() bind()
-
- // 1. call()
- var o = {
- name: 'andy'
- }
-
- function fn(a, b) {
- console.log(this);
- console.log(a + b);
- }
- fn.call(o, 1, 2);
- // call 第一个可以调用函数 第二个可以改变函数内的this 指向
- // call 的主要作用可以实现继承
- function Father(uname, age, sex) {
- this.uname = uname;
- this.age = age;
- this.sex = sex;
- }
-
- function Son(uname, age, sex) {
- Father.call(this, uname, age, sex);
- }
-
- var son = new Son('刘德华', 18, '男');
- console.log(son);
-
Son构造函数想继承Father构造函数的属性,在Son构造函数中,调用Father构造函数,同时改变this指向,让其指向Son构造函数。这个时候用到了call函数。
实现继承的过程: 创建一个Son的实例化对象son,这时把‘xiaoming’,18分别传给function Son(uname, age)中的uname,age,此时形参uname=‘xiaoming’; age=18; 然后function Son(uname, age)中有一个函数Father.call(this, uname, age),这里的uname和age就是形参,所以他们此时也有了对应的值,然后第一个参数改为this,Son构造函数里面的this应该指向它的实例化对象,也就是这里的son。带着这三个参数去调用Father函数,也就是son的uname属性赋值为形参uname的值‘xiaoming’,son的属性赋值为形参age的值18。实现了继承。
apply()方法可以立即调用一个函数,并可以改变该函数的this指向。
使用方法: fun.apply(thisArg,[argsArray])
因为它传入的参数是一个数组,所以我们可以用它处理一些和数组有关的问题,比如借用Math.max()求数组的最大值/最小值。
- <script>
- // 改变函数内this指向 js提供了三种方法 call() apply() bind()
-
- // 2. apply() 应用 运用的意思
- var o = {
- name: 'andy'
- };
-
- function fn(arr) {
- console.log(this);
- console.log(arr); // 打印出来的不是数组,而是字符串pink
- }
- fn.apply(o, ['pink']);
- // 1. 第一个也是调用函数 第二个可以改变函数内部的this指向
- // 2. 但是它的参数必须是数组(伪数组)
- // 3. apply 的主要应用 比如说我们可以利用 apply 借助于数学内置对象求最大值
- // Math.max();
- var arr = [1, 66, 3, 99, 4];
- // var max = Math.max.apply(null, arr);
- var max = Math.max.apply(Math, arr);
- var min = Math.min.apply(Math, arr);
- console.log(max, min);
- // 如果传递的数组里面是字符串型的,打印出来的就是字符串型的;如果传递的数组里面是数字型的,打印出来的就是数字型的
- script>
Math.max是一个方法(函数),对其使用apply方法,这里不需要改变this指向,所以第一个参数让它指回Math,第2个参数传入要处理的数组即可。这样就可以借用Math方法处理数组了。
apply方法会自动将传入的数组处理为对应的数据类型。
bind函数不会直接调用函数,但是可以改变函数内部的this指向,应用非常广泛。
使用方法: fun.bind(thisArg,arg1,arg2,…)
因此当我们只是想改变 this 指向,并不想立即调用这个函数的时候,可以使用bind,比如改变定时器的this指向。
比如有一个需求,点击某个按钮后,按钮被禁用,2秒后恢复正常。这里定时器里面的this指向的是window,而我们想让它指向当前被点击的button,因此需要修改this指向,但是我们又不希望它立即调用,而是等到满足定时器的条件后才执行,所以要用到bind函数。
这里有一个很巧妙的点,所以function () { this.disabled = false; }.bind(this) 中this已经在定时器的外面了,所以他不再是指向window,而定时器外面的环境是按钮点击事件,也就是说this指向的是当前点击的btn,而通过bind函数,巧妙的把定时器函数的this指向改成了当前点击的btn,就可以实现当前功能。
- <body>
- <button>点击button>
- <button>点击button>
- <button>点击button>
- <script>
- // 3. bind()
- var o = {
- name: 'andy'
- };
- function fn(a, b) {
- console.log(this);
- console.log(a + b);
- };
- var f = fn.bind(o, 1, 2);
- f(); // 3
- // 1. 不会调用原来的函数 可以改变原来函数内部的this 指向
- // 2. 返回的是原函数改变this之后产生的新函数
- // 3. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向 此时用bind
- // 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
- // var btn1 = document.querySelector('button');
- // btn1.onclick = function() {
- // this.disabled = true; // 这个this 指向的是 btn 这个按钮
- // // var that = this; // 方法1
- // setTimeout(function() {
- // 定时器函数里面的this 指向的是window
- // // that.disabled = false; // 方法1
- // 方法2:用bind()改变this指向,bind在setTimeout函数的外面
- // this.disabled = false; // 此时定时器函数里面的this 指向的是btn
- // }.bind(this), 3000); // 这个this 指向的是btn 这个对象
- // }
- var btns = document.querySelectorAll('button');
- for (var i = 0; i < btns.length; i++) {
- btns[i].onclick = function() {
- this.disabled = true;
- setTimeout(function() {
- this.disabled = false;
- }.bind(this), 3000);
- }
- }
- script>
- body>
相同点:
不同点:
主要应用场景: