this是函数内部的一个特殊对象,this引用的是函数据以执行的环境对象(关于环境对象我们会在文章最后作补充说明),在调用函数前this的值并不确定,不同的调用方式会导致this值的改变。
window.num = 22; var o = {num: 11}; function sayNum(){ alert(this.num) } sayNum();//22 o.sayNum = sayNum; o.sayNum();//11
记住:函数名仅仅是一个包含指针的变量而已。因此即使是在不同的环境中执行,全局的sayNum()函数与o.sayNum()指向的仍然是同一个函数。
1.全局作用域中调用函数时
全局作用域中调用,this对象引用的是window
匿名函数的执行具有全局性,因此其this对象通常也指向window
function fn1(){ console.log(this); } fn1();
2.通过new操作符调用
this引用的是实例对象
function Person(name){ this.name = name; } Person.prototype.printName = function(){ alert(this.name);//Byron }; var p1 = new Person('Byron');
3.作为对象的方法调用
this引用的是该对象
var obj1 = { name: 'Byron', fn : function(){ console.log(this); } }; obj1.fn();
4.间接调用
call和apply
每个函数都包含两个非继承而来的方法:call()和apply()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。也就是说,直接调用函数,调用时指定执行环境是谁
window.color = 'red'; var o = {color: 'blue'}; function sayColor(){ alert(this.color); } sayColor.call(this);//red sayColor.call(window);//red sayColor.call(o);//blue
(1)apply方法
接收两个参数,一个是在函数中运行函数的作用域,另一个是参数数组。
(2)call方法
call方法与apply方法相同,区别在于接收参数的方式不同,对于call方法而言,第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。
function fn(){ console.log(this)//windwow function InnerFn(){ console.log(this) } InnerFn.call(this)//window } fn(); function fn0(){ console.log(this)//window } function fn1(){ fn0.call(this); console.log(this);//window } fn1(); function fn0(){ console.log(this)//object } var o = { fn1: function fn1(){ fn0.call(this); console.log(this);//object } } o.fn1();
5.bind方法
这个方法会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。也就是说会返回一个新函数,并且使函数内部的this为传入的第一个参数
window.color = 'red'; var o = {color : 'blue'}; function sayColor(){ alert(this.color) } var objectSayColor = sayColor.bind(o); objectSayColor();//blue
补充说明:执行环境定义
定义了变量或者函数有权访问的其他数据,每个执行环境都有一个与之相关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。我们编写的代码无法访问这个对象,但解析器会在处理数据时在后台使用它。
一、执行环境的创建:
1.全局执行环境
在web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。代码载入浏览器时,全局执行环境被创建(当我们关闭网页或者浏览器时全局执行环境才被销毁)。
2.局部执行环境
每个函数都有自己的执行环境,因此局部执行环境为函数对象。当函数被调用时函数的局部环境被创建(函数内的代码执行完毕后,该环境被销毁,同时保存在其中的所有变量和函数定义也随之被销毁)。
这个执行环境以及相关的变量对象是个抽象的概念,解释如下
var a = 1; function fn(num1,num2){ var b = 2; function fnInner(){ var c = 3; alert(a + b + c); } fnInner();//fnInner调用时局部执行环境创建 } fn(4,5);//fn调用时局部执行环境创建
二、作用域链
javascript函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的,当定义一个函数时,它实际保存一个作用域链。当调用这个函数时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的作用域链。作用域链的前端始终都是当前执行的代码所在环境的变量对象。作用域链的末端始终都是全局执行环境的变量对象。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有权访问
var scope = 'global scope'; function checkscope(){ var scope = 'local scope'; function f(){return scope}; return f; } checkscope()();//local scope