this应该放在《上下文环境和作用域》中来讲
概念
在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了
因为this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文的环境。
构造函数
所谓的构造函数就是用来new对象的函数。其实严格来说,所有的函数都可以new一个对象,但是有些函数的定义是为了new一个对象,而有些函数则不是。另外注意,构造函数的函数名第一个字母大写(规则约定)。例如:Object、Array、Function等。
function Foo(){
this.name="yzh";
this.year=1996;
console.log(this);//Object{name:"yyq",year:1987}
}
var f1=new Foo();
console.log(f1.name);//yyq
console.log(f1.year);//1987
以上代码中,如果函数作为构造函数用,那么其中的this就代表他即将new出来的对象。
注意,以上仅限new Foo()的情况,即Foo函数作为构造函数的情况。如果直接调用Foo函数,而不是new Foo(),情况就不一样了。
funtion Foo(){
this.name="yyq"
this.year=1987;
console.log(this);//Object{name:"yzh",year:1998}
}
Foo();//window
这种情况下this是window。
函数作为对象的一个属性
如果函数作为对象的一个属性时,并且作为对象的一个属性被调用时函数中的this指向该对象。
var obj={
x:10,
fn:function(){
console.log(this);//Object{x:10,fnfn()}
console.log(this.x);//10
}
};
obj.fn();
以上代码中,fn不仅作为一个对象的一个属性,而且的确是作为对象的一个属性被调用。结果this就是obj的对象。
如果fn函数不作为obj的一个属性被调用,会是什么结果呢?
var obj={
x:10,
fn:function(){
console.log(this);//Object{x:10,fnfn()}
console.log(this.x);//10
}
};
var f1=obj.fn;
f1();
如上代码,如果fn函数被赋值到了另一个变量中,并没有作为obj的一个属性被调用,那么this的值就是window,this.x为undefined。
函数用call或者apply调用
为了防止看不懂这块先理解一下基础的重要的东西。
函数内部属性
在函数内部,有两个特殊的对象:arguments和this。
主要介绍下arguments,它是类数组对象,包含传入函数的所用参数,这个对象有一个叫callee的属性,该属性为一个指针,指向拥有这个arguments对象的函数。
这个例子主要用于消除函数的执行与同名函数的紧密耦合现象。代码如下:
function factorial(num){
if(num<=1){
return 1;
}else{
// return num*factorial(num-1);
// 1.一般的递归算法运用
return num*arguments.callee(num-1);
//2.更好的做法
}
}
var trueFactorial =factorial;
factorial=function(){
return 0;
};
alert(trueFactorial(5));//120
alert(factorial(5));//0
函数属性
每个函数都包含两个属性:length和prototype
length表示函数希望接受的命名参数的个数
function sayName(name){
alert(name);
}
function sum(num1,num2){
return num1+num2;
}
function sayHi(){
alert("h1");
}
alert(sayName.length);//1
alert(sum.length);//2
alert(sayHi.length);//0
prototype 属性这里不再重复介绍。
函数方法
每个函数都包含两个非继承而来的方法:apply()和call(),这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象值。
apply()方法接受两个参数:一个是在其中运行函数的作用域,另一个是参数数组。
function sum(num1,num2){
return num1+num2;
}
function callSum1(num1,num2){
return sum.apply(this,arguments);
}
function callSum2(num1,num2){
return sum.apply(this,[num1,num2]);
}
alert(callSum1(10,10));//20
alert(callSum2(10,10));//20
callsSum1()执行sum()函数时传入this作为this值(在全局作用域中调用,所有传入的对象为window对象)下面的例子同理。
call()方法与apply()方法差不多,区别在于接受参数的方式不同。简单来说就是:传递给函数的参数必须逐个列举出来。(如果是无参数函数就不用传参数)
function sum(num1,num2){
return num1+num2;
}
function callSum(num1,num2){
return sum.call(this,num1,num2);
}
alert(callSum(10,10));//20
传递参数并非两个函数的真正用武之地,真正强大的地方是扩充函数赖以运行的作用域
window.color="red";
var o={color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue
如下代码如果不用函数的方法来实现。
window.color="red";
var o={color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();//red
o.sayColor=sayColor;
o.sayColor();//blue
如果要输出o对象里的color属性值,必须把sayColor函数赋值给对象o并调用o.sayColor()时,this引用的对象为o。
回归要讲的例子
当一个函数被call和applay调用时,this的值就取传入对象的值
var obj={
x:10;
};
var fn=function(){
console.log(this);//Object{x:10;}
console.log(this.x);//10
};
fn.call(obj);
全局&调用普通函数
在全局环境下,this永远是window,这个应该没有非议。
console.log(this===window);//true
普通函数在调用时,其中的this也都是window。
var x=10;
var fn=function(){
console.log(this);//window
console.log(this.x);//10
}
fn();
注意以下情况
var obj={
x:10,
fn:funciton(){
function f(){
console.log(this);//window
console.log(this.x);//underfined
}
f();
}
};
obj.fn();
函数f虽然是在obj.fn内部定义的,但是它仍然是一个普通的函数,this仍然指向window
总结:this指向调用该函数的对象
构造函数的prototype中,this代表着什么
function Fn(){
this.name="yyq";
this.year=1987;
}
Fn.prototype.getName=function(){
console.log(this.name);
}
var f1=new Fn();
f1.getName();//yyq
在,Fn.prototype.getName函数中,this指向的是f1对象。因此可以通过this.name获取f1.name的值。
bind()
bind()方法创建一个新的函数,当被调用时,它的this关键字被设置为提供的值,在调用新函数时,提供任何一个给定的参数序列。
语法
fun.bind(thisArg[,arg[,arg2[,....]]])
参数
thisArg
当绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用new操作符调用绑定函数时,该参数无效。
arg1,arg2
当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
返回值
返回有指定的this值和初始化参数改造的原函数拷贝
描述
bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
示例
创建绑定函数
this.x=9;
var module={
x:81,
getX:function(){
return this.x;
}
};
module.getX();//返回81;
var retrieveX=module.getX;
retrieveX();// 返回 9, 在这种情况下,"this"指向全局作用域
// 创建一个新函数,将"this"绑定到module对象
// 新手可能会被全局的x变量和module里的属性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81