一.理解this指针意义
二.用call(),apply(),bind()解决指针指向问题
三.bind()的使用场景与少用之处html
让咱们先理解好this指针的定义:segmentfault
this引用的是函数执行的环境对象
数组
this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的
闭包
通俗地讲,就是谁调用this,this就指向谁,咱们分类举例app
举例前先看下本文会一直用到的变量及定义的函数函数
var theName = "Joe"; //全局变量 function showName() { var theName = "Li"; alert(this.theName); }
showName(); //弹出“Joe”
由于是window对象调用showName()
,因此this指向window啦,故弹出"Joe"this
var student1 = { theGrade : 100, theName : "Han", showName : showName, showGrade : function () { alert(this.theGrade); } }; student1.showName();//弹出“Han” student1.showGrade();//弹出“100”
由于是在student1对象调用函数
,故弹出的是对应student1对象中的"Han"和“100”啦spa
var student2 = { theGrade: 60, showGrade: student1.showGrade }; student2.showGrade(); //弹出"60"
即便student2对象
调用了student1对象下的方法showGrade()
,由于是student2对象调用
,故弹出的还是student2的"60"prototype
var outFunction = student1.showGrade; outFunction();//弹出“undefined”
将sutdent1对象的函数赋值给oufFuncction,而outFunction是在window对象下调用的
,故弹出“undefined”设计
function setStudent() { this.theName = "Ming"; } var student3 = new setStudent(); alert(student3.theName);//弹出“Ming”,new改变this指向
构造函数下,new改变了指针指向,指向了student3
关键:闭包保存建立时的环境!!!
举个例子
为了更好理解闭包与指针的关系,咱们先定义一个全局变量,一个函数,和一个对象
var example = 'window';//全局变量 function showExample() { console.log(this.example); } var exampleObject = { example : 'Object', showExample_in_Object : function (arg1, arg2) { console.log(this.example); console.log(arg1,arg2) } };
接着,咱们设置一个事件监听来讲明问题:
//事件监听 var btn = document.getElementById("btn"); btn.onclick = function (ev) { console.log(this); //this指向按钮,执行匿名函数的是btn this.example = 'ele'; console.log(this.example);//弹出"ele" showExample(); //闭包保存函数建立时的环境,故this指向window对象 exampleObject.showExample_in_Object();//this指向exampleObject };
结果:
接下来分段说明各个指针
其中
this.example = 'ele'; console.log(this.example);
其中的this指向btn
,因此显示的是‘ele’
而
showExample(); exampleObject.showExample_in_Object();
在匿名函数中为闭包,闭包保存函数建立时的环境,故this分别指向window和exampleObject
补充对闭包中this的理解:https://segmentfault.com/q/10...
以上是部分this指针的理解
若是我在事件监听中想要减小代码重复
,或者是调用其余对象的属性
呢?
若是我想用btn.addEventListener()时指向的某个特定对象
呢?
这就能够引出下面call(),apply()与bind()的应用了
function User(id){ this.id = id; } User.prototype.test = function(){ console.log(this);//指向b对象 (function(){ console.log(this) //指向window })() } var a = new User('a') a.test();
由于自执行函数是由window执行的
若是此时使用箭头函数
function User2(id){ this.id = id; } User.prototype.test = function(){ console.log(this); //指向b对象 (() =>{ console.log(this) //指向b对象 })() } var b = new User2('b'); b.test();
由于箭头函数不会绑定this,因此指向上一层的b对象
call()与apply()的做用都是在特定的做用域中调用函数
,实际上等于设置函数体内设置this对象的值
简单地说,就是能够改变函数的执行环境
call()与allpy()效果相同,仅是传参形式不一样,以下所示
call(): fun.call(thisArg, arg1, arg2, ...) thisArg : fun函数运行时指定的this值 arg1,arg2,.. (可选):指定的各个参数
apply(): func.apply(thisArg, [argsArray]) thisArg : fun函数运行时指定的this值 [argsArray](可选) : 传参数组或者传参类数组
下面直接看例子吧
咱们以上面的例子进行修改,为了对比传参的形式,咱们对showExample函数添加两个参数
function showExample(arg1,arg2) { console.log(this.example); console.log(arg1,arg2); }
接下来即是btn的点击事件函数修改,咱们令showExample函数指向exampleObject
//call与apply的应用 btn.onclick = function (ev) { showExample.call(exampleObject,111,222); //弹出'Object' ,111与222是传参示例 showExample.apply(exampleObject,[111,222]); //弹出'Object' ,[111,222]是传参示例 }; 弹出'Object' ,111与222是传参示例 showExample.apply(exampleObject,[111,222]); //弹出'Object' ,[111,222]是传参示例 };
如上,经过call()与apply()的应用,能够改变函数的指向而屡次运用
若是我想便于调试
想使用ele.addEventListener()嘞?
这就要用上bind()方法了
fun.bind(thisArg[, arg1[, arg2[, ...]]])
MDN : bind()方法建立一个新的函数, 当被调用时,将其this关键字设置为提供的值, ,在调用新函数时,在任何提供以前提供一个给定的参数序列。
咱们再举个简单的例子,将exampleObject简单修改下
var exampleObject = { example : 'Object', showExample_in_Object : function (arg1, arg2) { console.log(this); console.log('example:'+ this.example); console.log('arg1:' + arg1); console.log('arg2:' + arg2); } };
并把showExample_in_Object()函数添加给btn
注意这里的是函数,不是闭包!
btn.addEventListener('click',exampleObject.showExample_in_Object);
控制台显示以下
能够看出this指向的是btn
,而没法知足咱们使用exampleObject中属性的须要,同时也没法进行传参(用call()与apply()就直接执行函数了!)
(这里的没有对第一个参数arg1进行传参,故默认显示MouseEvent对象)
这时咱们能够用bind()方法建立一个新的函数
,并让其指针指向exampleObject
,并传两个新的参数进去
btn.addEventListener('click',exampleObject.showExample_in_Object.bind(exampleObject,111,222));
当当~指针指向了exampleObject,传参也成功了~
另外,这里也有个能够不使用bind()的方法,就是也用闭包
啦
btn.addEventListener('click',function () { exampleObject.showExample_in_Object(111,222); });
结果同样,但这种方法不利于代码的维护
,同时也没法指向特定的对象
使用场景:主要用于如上的事件监听
,以及setTimeout()
和setInterval()
少用之处:被绑定的函数与普通函数相比有更多的开销,它们须要更多的内存
,同时也由于多重函数调用稍微慢一点,因此最好只在必要时使用
以上,若有不对之处,请你们指教
完全理解this指针: https://www.cnblogs.com/pssp/...
MDN:bind(): https://developer.mozilla.org...
MDN:apply():https://developer.mozilla.org...
MDN:call(): https://developer.mozilla.org...
《JavaScript高级程序设计(第3版)》
《JavaScript语言精粹》