js中怎么改变this指向

call和apply来自Function.prototype;
所以所有的函数都可以使用;
特点是可以自由指定函数内部的this;
区别是传参的方式不同。

call()


    语法: 函数.call(this, arg1, arg2, arg3, arg4)
    第一个参数用来指定函数内部的this指向,后面的参数是函数执行时所需的实参。
   
   
     
     
  1. function add(a, b) {
  2. console.log(this.length + a + b);
  3. }
  4. add.call([1, 2, 3], 10, 50);

apply()


    语法: 函数.apply(this, []);
    第一个参数用来指定函数内部的this指向;
    第二个参数要求是一个数组或者伪数组,apply会把它平铺然后传入对应的函数中.
    可以平铺数据;
   
   
     
     
  1. function add(a, b) {
  2. console.log(this.length + a + b);
  3. }
  4. add.apply([1, 2, 3], [10, 50]);

bind方法


* es5在Function.prototype上新增了一个bind方法,
* 该方法返回一个函数,这个函数可以认为是绑定了this的clone版本。
* 语法:新函数 = 函数.bind(this)
*
* bind和call、apply的异同:
* 1、相同之处是都可以改变函数运行时内部的this
* 2、不同之处是call和apply是一次性改变this,bind是永久性改变this
*
* 可以认为bind的灵活性更高,你可以先把this绑定好,
* 然后什么时候想执行就什么时候执行。
* */

function fn() {
    console.log(this.length);
}

// newFn相当于是fnclone版本,但是this为固定化了
var newFn = fn.bind([1,2,3,4]);
newFn();
newFn();
newFn();

// 可以利用bind得到多个fnclone版本
var newFn2 = fn.bind('好吧');
newFn2();
newFn2();

call、apply对不同参数this的处理


       1、不传参,或者传入null和undefined,this指向window;        2、传入基本数据类型(null和undefined除外),this指向他们的包装对象;        3、传入的是对象,this就指向这个对象;
    
    
  1. function fn() {
  2. console.log(this);
  3. }
  4. // this为window
  5. fn.call();
  6. fn.apply(null);
  7. fn.apply(undefined);
  8. // this为对应的包装对象
  9. fn.apply(1);
  10. fn.apply('abc');
  11. fn.call(false);

模拟call 和 apply 方法

// 函数调用该方法,可以指定函数的this
Function.prototype.myApply = function(param) {
    /*2
    * 实现思路:
    * 1、把函数存储到指定的this
    * 2、通过指定的this调用函数,实现一个方法调用模式,这样函数的this就是指定的this
    * */

    // 这里的this,谁调用myApply,就是谁
    param.__fn__ = this;

    // myApply内部,反回来再调用this(调用myAppy的那个函数)    // 但是调用模式发生了改变,造成函数的this发生了改变。
    param.__fn__();

    // __fn__使用完毕后,删除掉
    delete param.__fn__;
};

利用call 和 apply 借用其他数据类型方法

/*
* callapply可以借用其他对象的方法去操作指定的对象。
*
* 通常实例的方法内部在实现时,都会使用this来获取对应的实例,
* 即这些方法内部操作的都是this
*
* 如果一个方法内部没有操作this,那么是无法借用成功的。
*
* 借用一个方法操作我们指定的对象,如何操作需要看这个方法具体的功能。
* */

/*// 给所有的数组添加一个遍历打印值的方法 conArr
Array.prototype.conArr = function() {
    // 这里通过this,可以获取调用conArr方法的数组,
    // 那么谁调用这个方法,我们就打印谁的值。
    var i, len;
    for (i = 0, len = this.length; i < len; i++) {
        console.log(this[i]);
    }
};

// 数组调用这个,依次打印123
var arr = [1,2,3];
arr.conArr();

var arr2 = ['a','b','c'];
arr2.conArr();*/


/*------------------------------------------*/

// 这是一个伪数组对象
var obj = {
    0: 'abc',
    1: 'qwe',
    2: 'wsx',
    3: 'edc',
    name: '肥猫',
    age: '3',
    length: 5
};

/*// 伪数组不是真数组,无法调用真数组的那些方法。
//obj.conArr();

// 但是我们还想利用数组的conArr方法,打印伪数组中下标存储的数据。
// conArr方法有一个特点,它内部操作的是this
// 如果我们能够让这个this指向obj,那么conArr就可以操作obj了。
//Array.prototype.conArr.call(obj);
[].conArr.call(obj);

// 既然可以通过call借用数组的conArr方法,那么其他方法是否可行呢?

// 借用push方法给伪数组添加新值
[].push.call(obj, 10, 20, 30, 40, 50);
console.log(obj);

// 借用pop删除伪数组中最后一个值
[].pop.call(obj);
console.log(obj);*/

// 借用slice截取伪数组的一部分,得到一个新数组
//console.log([].slice.call(obj, 1));

// 如果一个伪数组需要多次使用真数组的那些方法,可以考虑把伪数组转化为真数组
console.log([].slice.call(obj));  // slice在截取的时候,只会截取存在的值
console.log([].concat.apply([], obj)); // apply会根据length平铺得到所有的值传给concat



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值