1:this
javascript中的this总是指向一个对象的,至于是指向哪一个对象,是运行时基于函数的执行环境的动态绑定的,尔非函数被声明时的环境;
this的指向可以分为四类:
- 作为对象的方法调用
- 作为普通函数调用
- 构造器调用
- Function.prototype.call()和Function.prototype.apply()
1.1:作为对象的方法调用:
当函数作为对象的方法被调用时,this指向该对象
//obj对象 var obj={ name:name; getName:function(){ concole.log(this===obj); //输出true console.log(this.name); //输出name } }; obj.getName();
1.2作为普通函数调用:
当函数不作为对象的属性被调用时,也就是以普通函数方式,this指向全局对象,在浏览器的javascript中,全局对象指的是winows对象
window.name=‘globalName’; //声明全局对象name的属性 var getName=function(){ return this.name; } console.log(getName()); //输出globalName; window.name='globalName'; //声明全局对象name的属性 var obj={ name:'myObjName', getName:function(){ return this.name; }, } var myobj=obj.getName; console.log(myobj()); //输出globalName;
1.3构造器调用:
javascript没有类,可以从构造器中创建对象,也提供了new运算符调用构造器。大部分javascript函数都可以当做构造器使用,构造器的外表和普通函数并没有什么两样,区别就是被调用的方式,即使用new运算符创建对象时,就是将函数当做构造器调用。当用new运算符调用函数时,该函数总会返回一个对象,此时,构造器里的this指向返回的这个对象。
var myClass=function(){ this.name='classname'; }; var obj=new myClass(); console.log(obj.name); //输出classname
但,如果构造器显式地返回了一个object类型的对象,那么此函数将返回这个object类型的对象,而不是函数本身所定义的对象,例如:
var myClass=function(){ this.name='classname'; return{ name:'lihe' }; }; var obj=new myClass(); console.log(obj.name); //输出lihe
而,如果构造器不显式地返回任何数据,或返回一个非对象类型的数据,就不会造成上述情形。
var myClass=function(){ this.name='classname'; return 'lihe'; }; var obj=new myClass(); console.log(obj.name); //输出classname
1.4.Function.prototype.call 或 Function.prototype.apply调用
跟普通函数调用相比,用 Function.prototype.call
或 Function.prototype.apply
可以动态地改变传入函数的this。
var A={ name:'classnameA', getName:function(){ return this.name; }, }; var B={ name:'classnameB', }; console.log(A.getName()); //classnameA console.log(A.getName.call(B)); //classnameB
丢失的this:
当this的指向,与我们期待的不同时,就会出现undefined情况
var obj={ name:'classname', getName:function(){ return this.name }, }; //作为对象的方法引用,指向obj对象 console.log(obj.getName()); //输出classname //作为普通函数调用,指向全局对象window,name属性还没定义 var getName2=obj.getName; console.log(obj.getName2); //输出undefined
2 call和apply
Function原型的两个方法Function.prototype.call() Function.prototype.apply()
call和apply区别:作用一样,传入参数形式不同
apply接受两个参数,第一个参数制定了函数体内this对象的指向,第二个函数为一个带下标的集合,这个集合可以是数组,也可以是类数组。apply方法把这个集合中的元素作为参数传递给被调用的函数。
var func = function(a, b, c){ console.log([a, b, c]); }; func.apply(null, [1, 2, 3]);
call传入的参数数量不固定,第一个参数也是代表了函数体内的this指向,从第二个参数开始往后,每个参数依次被传入函数:
var func = function(a, b, c){ console.log([a, b, c]); }; func.call(null, 1, 2, 3);
当使用call或apply的时候,如果我们传入的第一个参数为null,函数体内的this会指向默认的宿主对象,在浏览器中则是window:
var func = function(a, b, c){ console.log(this); }; func.apply(null, [1, 2, 3]); //输出:window对象 func.call(null, 1, 2, 3); //输出:window对象
3.call() 和apply()用途
-
改变this指向
-
Function.prototype.bind
-
借用其他对象的方法
3.1改变this指向:改变函数内部this的指向
var A = { name: 'nameA', }; var B = { name: 'nameB', }; window.name = 'nameWindow'; var getName = function(){ console.log(this.name); }; getName(); // 以普通函数调用,指向了window对象,输出nameWindow getName.call(A); // 改变了this的指向,指向了传入的对象,输出:nameA getName.call(B); // 改变了this的指向,指向了传入的对象,输出:nameB
3.2Function.prototype.bind
大部分高级浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this指向。若没有原生的Function.prototype.bind实现,可以通过模拟一个:
Function.prototype.bind = function(context){ var self = this; // 保存原函数 return function(){ // 返回一个新的函数 return self.apply(context, arguments); // 执行新函数的时候,会把之前传入的context当作新函数体内的this } }; var obj = { name: "objName" }; var func = function(){ console.log(this.name); }.bind(obj); func(); // 输出:objName
3.3借用其他对象的方法
- 类数组对象的操作
想把arguments转成真正的数组的时候,可以借用Array.prototype.slice方法;
想往arguments中添加一个新的元素,可以借用Array.prototype.push:
想截去arguments列表中的头一个元素时,可以借用Array.prototype.shift方法。
(function(){ Array.prototype.push.call(arguments, 3); console.log(arguments); // 输出:[1,2,3] })(1, 2);
- 借用构造函数,可以实现类似继承
var A = function(name){ this.name = name; }; var B = function(){ // 借用A的构造函数 A.apply(this, arguments); }; B.prototype.getName = function(){ return this.name; }; var b = new B('baby'); console.log(b.getName()); // 输出:baby