对this我想作为前端来说接触的是很多的,可能只限于能用的层次,就很多面试题来说,要完全弄懂还是有点距离的,那么我们就来加强理解下吧,参考高三和语言精粹。
this和arguments是作为函数的两个特殊对象的,参数this在面向对象编程中非常重要,它的值取决于调用的模式,在js中一共有4种调用模式,
1,方法调用模式
当一个函数保存为一个对象的属性时,我们称之为一个方法,当这个方法被调用的时候,this就被绑定到该对象,
var o = { val: 0, sayval: function(num){ if(typeof num === ‘number‘){ console.log(this.val + num) }else{ alert(‘请输入数字‘) } } } var val = 11; o.sayval(1);//1 o.sayval(2);//2
2,函数调用模式
当一个函数并非一个对象的属性时,那么它就是被当做一个函数调用的,当函数以此模式调用时,this被绑定到全局对象,
var o = { val: 0, sayval: function(num){ if(typeof num === ‘number‘){ console.log(this.val + num) }else{ alert(‘请输入数字‘) } } } var val = 11; var fn = o.sayval; fn(1);//12
这样设计的话,当内部函数被调用的时候,this应该绑定到外部函数的this变量,但是却被绑定到了全局,这里有个解决的办法,定义一个变量并给它赋值为this,
var o = { val: 0, sayval: function(num){ var that = this; var other = function() { if(typeof num === ‘number‘){ console.log(that.val + num) }else{ alert(‘请输入数字‘) } }; other(); } } var val = 11; o.sayval(1);//1 方法调用模式
这里是不是有点混了,刚开始我也有点混淆了,刚讲过,方法调用模式this会被绑定到全局,怎么这样做却是绑定到o这个对象了呢,区别在于第7行,若是将that改为this,结果就是12了,在这大胆的分析下函数执行逻辑吧,如果是this,方法调用,绑定到全局对象,this就是window.this,如果是that就不一样了,that是变量,那函数执行的时候就会根据作用域去寻找这个变量值,other函数没有就向上找,(变量作用域的知识),找到sayval里面的that,这个变量指向的this,而这里的this指的就是o这个对象。
这样给我们的启示是如果想调用这个函数的外部函数的属性,就在外部函数保存this值,再在内部函数中调用,然后再用方法调用模式去调用函数。
作为浏览器兼容性中很重要的一条:element.attachEvent绑定事件方法,当该事件触发时this指针并未绑定到element对象上,而是绑定到了window对象上,原因在于IE中事件触发时,响应函数是以一个独立函数即函数调用模式来调用的。
3,构造器模式调用
javascript 是一门基于原型继承的语言,这意味着对象可以直接从其他对象继承属性。
如果在一个函数前面带上new来调用,那么将创建一个隐藏连接到该函数的prototype成员的新对象,同时this将会被绑定到那个新对象上,new前缀会改变return语句的行为。
var P = function(n){ this.name = n; } P.prototype.getName = function(){ console.log(this.name); } var p = new P(‘jesse‘); // 这时P中的this对象呗绑定p指向的对象引用上 p.getName();//jesse
同时new运算符还会改变函数的返回值。以函数调用模式调用P即P()返回undefined,而通过new运算符则返回一个新对象。
4,apply,call调用模式
apply方法让我们构建一个参数数组传递给调用函数。它也允许我们选择this的值,apply的方法接受两个参数,第1个是要绑定给this的值,第2个是参数数组(call的话后边是一个一个的参数)。
var add = function(a, b){ return a + b; }; var arr = [3, 4]; var sum = add.apply(null, arr); console.log(sum);//7