js中修改this的指向

方法整理

call,apply,bind

以上的三哥方法都是用来改变js中this的指向

  • call

    使用方法:fun.call(thisArg[,arg1[, arg2[, ...]]])

    该方法传递一个thisArgs和一个参数列表,thisArgs制定了函数在运行中的调用者,也就是函数中的this对象,而参数列表会被传入调用函数中。

    call 方法可以在一个对象上借用另一个对象的方法

    案例:Object.prototype.tostring.call([])。一个Array对象借用了Object对象上的方法

    thisArgs的取值情况:

    (1) 不传,或者穿null,undefined,函数中的this指向window对象。

    (2)传递另一个函数的函数名,函数中的this指向这个函数的引用

    (3)传递字符串,数值或者不二类型的那个基础数据类型,函数中的this指向其对应的包装对象,如string,number,boolean

    (4)传递一个对象,函数中的this指向这个对象。
function a (){
console.log(this)
//输出函数a中的this对象
}
function b(){
}//定义函数b
var obj = {name:“onepixel”};//定义对象obj
a.call(); //window
a.call(null); //window
a.call(undefined);//window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b);// function b(){}
a.call(obj); //Object

这是call的核心功能,它允许你在一个对象上调用该对象没有定义的方法,并且这个方法可以访问该对象中的属性

var a = {
name:'onepixel', //定义a的属性
say:function(){ //定义a的方法
console.log("Hi,I'm function a!");
}
};
function b(name){
console.log("Post params: "+ name);
console.log("I'm "+ this.name);
this.say();
}
b.call(a,'test'); //将b的this指向a,参数是b的

还可以通过call方法来调用匿名函数

在下例中的for循环体内,我们创建了一个匿名函数,然后通过调用该函数的call方法,将每个数组元素作为指定的this值执行了那个匿名函数。这个匿名函数的主要目的是给每个数组元素对象添加一个print方法,这个print方法可以打印出各元素在数组中的正确索引号。当然,这里不是必须得让数组元素作为this值传入那个匿名函数(普通参数就可以),目的是为了演示call的用法。

var animals = [
{species: 'Lion', name: 'King'},
{species: 'Whale', name: 'Fail'}
]; for (var i = 0; i < animals.length; i++) {
(function (i) {
this.print = function () {
console.log('#' + i + ' ' + this.species + ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}
//#0 Lion: King
//#1 Whale: Fail

apply()方法

fun.apply(thisArg[, argsArray])

apply和call的唯一区别是第二个参数的传递方式不同,apply的第二个参数必须是一个数组,而call允许传递一个参数列表。值得你注意的是,虽然apply接收的是一个参数数组,但在传递给调用函数时,却是以参数列表的形式传递。

注意:这里的argsArray可以是一个数组或者类数组对象,如果该参数的值为null 或 undefined,则表示不需要传入任何参数。

function b(x,y,z){
console.log(x,y,z);
}
b.apply(null,[1,2,3]); // 1 2 3

apply方法的实用写法

//里面有最大最小数字值的一个数组对象
var numbers = [5, 6, 2, 3, 7]; /* 使用 Math.min/Math.max 在 apply 中应用 */
var max = Math.max.apply(null, numbers);
// 一般情况是用 Math.max(5, 6, ..) 或者 Math.max(numbers[0], ...) 来找最大值
var min = Math.min.apply(null, numbers);

当参数是明确知道数量时用call;不确定的时候用apply,然后把参数push进数组传递进去,也可以通过arguments这个数组来遍历所有的参数。

bind()方法

fun.bind(thisArg[, arg1[, arg2[, ...]]])

bind是ES5新增的一个方法,它的传参和call类似,但又和call/apply有着显著的不同,即调用call或apply都会自动执行对应的函数,而bind不会执行对应的函数,只是返回了对函数的引用。

ES5中新增加的bind方法可以弥补call()和apply()方法的不足,由于call/apply会对目标函数自动执行,从而导致它无法在事件绑定函数中使用,因为事件绑定函数不需要我们手动执行,它是在事件被触发时由JS内部自动执行的。而bind在实现改变函数this的同时又不会自动执行目标函数,因此可以完美的解决上述问题,看一个例子就能明白:

当点击网页时,EventClick被触发执行,输出JSLite.io p1 p2, 说明EventClick中的this被bind改变成了obj对象。如果你将EventClick.bind(obj,'p1','p2') 变成 EventClick.call(obj,'p1','p2') 的话,页面会直接输出 JSLite.io p1 p2

var obj = {name:'JSLite.io'};
/**
* 给document添加click事件监听,并绑定EventClick函数
* 通过bind方法设置EventClick的this为obj,并传递参数p1,p2
*/
document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false);
//当点击网页时触发并执行
function EventClick(a,b){
console.log(
this.name, //JSLite.io
a, //p1
b //p2
)
}
// JSLite.io p1 p2

兼容写法

if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
} var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this, // this在这里指向的是目标函数
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP
? this //此时的this就是new出的obj
: oThis || this,//如果传递的oThis无效,就将fBound的调用者作为this //将通过bind传递的参数和调用时传递的参数进行合并,并作为最终的参数传递
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
//将目标函数的原型对象拷贝到新函数中,因为目标函数有可能被当作构造函数使用
fBound.prototype = new fNOP();
//返回fBond的引用,由外部按需调用
return fBound;
};
}

应用

通过call和apply实现继承:

function Animal(name,weight){
this.name = name;
this.weight = weight;
}
function Cat(){
Animal.call(this,'cat','50');
//Animal.apply(this,['cat','50']);
this.say = function(){
console.log("I am " + this.name+",my weight is " + this.weight);
}
}
var cat = new Cat();
cat.say();//I am cat,my weight is 50

js改变this指向的更多相关文章

  1. (三十七)js改变this指向的方法

    最近又遇到了JacvaScript中的call()方法和apply()方法,而在某些时候这两个方法还确实是十分重要的,那么就让我总结这两个方法的使用和区别吧. 1.改变函数内部的this指向的三种方法 ...

  2. 【面试题】JS改变this指向的三种方法

    一.this指向 点击打开视频讲解更加详细 this随处可见,一般谁调用,this就指向谁.this在不同环境下,不同作用下,表现的也不同. 以下几种情况,this都是指向window 1.全局作用下 ...

  3. js 改变this指向的三种方法 bind call apply

    先了解下bind call apply 的注意点 bind 需要手动调用 第一个参数 this 要指向的对象,后面是 散列的参数 call 不需要手动调用 第一个参数 this 要指向的对象,后面是 ...

  4. js中改变this指向的call、apply、bind 方法使用

    前言: 由于js 中this的指向受函数运行环境的影响,指向经常改变,使得开发变得困难和模糊,所以在封装sdk,写一些复杂函数的时候经常会用到this 指向绑定,以避免出现不必要的问题,call.ap ...

  5. 前端js中this指向及改变this指向的方法

    js中this指向是一个难点,花了很长时间来整理和学习相关的知识点. 一. this this是JS中的关键字, 它始终指向了一个对象, this是一个指针; 参考博文: JavaScript函数中的 ...

  6. JS中this指向问题和改变this指向

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  7. 关于js中this指向的理解总结!

    关于js中this指向的理解! this是什么?定义:this是包含它的函数作为方法被调用时所属的对象. 首先,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁 ...

  8. Atitit.js this错误指向window的解决方案

    Atitit.js this错误指向window的解决方案 1.1. 出现地点and解决之道1 1.2. call,apply和bind这三个方法2 1.2.1. Function.prototype ...

  9. setTimeout改变this指向(****************************************)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

随机推荐

  1. 笔记:npm常见错误

    常见错误 破坏的npm安装 随机错误 找不到兼容版本 权限错误 Error: ENOENT, stat 'C:\Users\<user>\AppData\Roaming\npm' 在Win ...

  2. 论文笔记 : NCF( Neural Collaborative Filtering)

    ABSTRACT 主要点为用MLP来替换传统CF算法中的内积操作来表示用户和物品之间的交互关系. INTRODUCTION NeuCF设计了一个基于神经网络结构的CF模型.文章使用的数据为隐式数据,想 ...

  3. Storm大数据实时计算

    大数据也是构建各类系统的时候一种全新的思维,以及架构理念,比如Storm,Hive,Spark,ZooKeeper,HBase,Elasticsearch,等等 storm,在做热数据这块,如果要做复 ...

  4. 2019 用友网络java面试笔试题 (含面试题解析)

    本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条. 用友网络等公司offer,岗位是Java后端开发,最终选择去了 用友网络. 面试了很多家公司,感觉大部分公司考察 ...

  5. RHEL6搭建网络yum源软件仓库

    RHEL的更新包只对注册用户生效,所以需要自己手动改成Centos的更新包 一.查看rhel本身的yum安装包 rpm -qa | grep yum 二.卸载这些软件包 rpm -qa | grep ...

  6. C#中的委托、事件及事件的订阅

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. js运算符及数据类型转换(二)

    1.一元运算符+.-[将其它类型转化为number类型,相当于调用了Number()函数]var num = +('hello')  NaN  typeof num->numbernum = + ...

  8. 【重大更新】Qlik Sense September 2018重磅发布(附下载)

    作为数据分析领域领导者,Qlik,始终致力于通过产品创新来帮助企业客户撬动数据力量.近日,Qlik Sense September 2018如期而至,不仅对原有版本进行了众多优化,还发布了一系列能够提 ...

  9. 魅族手机使用应用沙盒一键修改imsi数据

    较早前文章介绍了怎么在安卓手机上安装激活XPosed框架,XPosed框架的牛逼之处功能各位都介绍过,可以不修改apk的前提下,修改系统内核的参数,打比方在某些应用领域,各位需要修改手机的某个系统参数 ...

  10. 报错:failed to get the task for process XXX(解决方案)

    引文: iOS真机调试程序,报如下错误信息: 原因: 证书问题,project和targets的证书都必须是开发证书,ADHOC的证书会出现此问题. 解决方案: project和targets的证书使 ...