您的位置:首页 > Web前端 > JavaScript

js中怎么改变this指向

2017-03-21 15:39 381 查看
call和apply来自Function.prototype;

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


call()

   语法: 函数.call(this, arg1, arg2, arg3, arg4)
   第一个参数用来指定函数内部的this指向,后面的参数是函数执行时所需的实参。

function add(a, b) {

console.log(this.length + a + b);

}

add.call([1, 2, 3], 10, 50);



apply()

   语法: 函数.apply(this, []);
   第一个参数用来指定函数内部的this指向;
   第二个参数要求是一个数组或者伪数组,apply会把它平铺然后传入对应的函数中.

   可以平铺数据;

function add(a, b) {

console.log(this.length + a + b);

}


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相当于是fn的clone版本,但是this为固定化了
var newFn = fn.bind([1,2,3,4]);
newFn();
newFn();
newFn();

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



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

       1、不传参,或者传入null和undefined,this指向window;
       2、传入基本数据类型(null和undefined除外),this指向他们的包装对象;
       3、传入的是对象,this就指向这个对象;

function fn() {

console.log(this);

}


// this为window

fn.call();

fn.apply(null);

fn.apply(undefined);


// this为对应的包装对象

fn.apply(1);

fn.apply('abc');

fn.call(false);



模拟call 和 apply 方法

// 函数调用该方法,可以指定函数的this
Function.prototype.myApply = fun
cc30
ction(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 借用其他数据类型方法

/*
* call和apply可以借用其他对象的方法去操作指定的对象。
*
* 通常实例的方法内部在实现时,都会使用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]);
}
};

// 数组调用这个,依次打印1、2、3
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




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: