原本this应该放在《上下文环境和做用域》中来说,结果发现本身整理的时候,例子愈来愈多,因此单独写一篇用于加深理解,之后工做或项目中发现一些this相关问题能够进一步完善文章的例子。算法
在函数中this到底取何值,是在函数真正被调用执行的时候肯定的,函数定义的时候肯定不了数组
由于this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。app
所谓构造函数就是用来new对象的函数。其实严格来讲,全部的函数均可以new一个对象,可是有些函数的定义是为了new一个对象,而有些函数则不是。另外注意,构造函数的函数名第一个字母大写(规则约定)。例如:Object、Array、Function等。函数
function Foo() { this.name = "yzh"; this.year = 1996; console.log(this); //Object { name: "yzh", year: 1998 } } var f1 = new Foo(); console.log(f1.name); //yzh console.log(f1.year); //1996
以上代码中,若是函数做为构造函数用,那么其中的this就表明它即将new出来的对象。this
注意,以上仅限newFoo()的状况,即Foo函数做为构造函数的状况。若是直接调用Foo函数,而不是new Foo(),状况就大不同了。spa
function Foo() { this.name = "yzh"; this.year = 1996; console.log(this); //Object { name: "yzh", year: 1998 } } Foo(); //window
这种状况下this是window。prototype
若是函数做为对象的一个属性时,而且做为对象的一个属性被调用时,函数中的this指向该对象。指针
var obj = { x: 10, fn: function() { console.log(this); //Object { x: 10, fn: fn() } console.log(this.x); //10 } }; obj.fn();
以上代码中,fn不只做为一个对象的一个属性,并且的确是做为对象的一个属性被调用。结果this就是obj对象。code
若是fn函数不做为obj的一个属性被调用,会是什么结果呢?对象
var obj = { x: 10, fn: function() { console.log(this); //window console.log(this.x); //undefined } }; var f1 = obj.fn; f1();
如上代码,若是fn函数被赋值到了另外一个变量中,并无做为obj的一个属性被调用,那么this的值就是window,this.x为undefined。
为了防止看不懂这块先理解下基础并重要的东西
在函数内部,有两个特殊的对象: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("hi"); } 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和apply调用时,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: function() { function f() { console.log(this); //Window console.log(this.x); //undefined } f(); } }; obj.fn();
函数f虽然是在obj.fn内部定义的,可是它仍然是一个普通的函数,this仍然指向window。
总结:this指向调用该函数的对象
function Fn() { this.name = "yzh"; this.year = 1996; } Fn.prototype.getName = function() { console.log(this.name); } var f1 = new Fn(); f1.getName(); //yzh
在Fn.prototype.getName函数中,this指向的是f1对象。所以能够经过this.name获取f1.name的值
bind()方法建立一个新的函数, 当被调用时,它的this关键字被设置为提供的值 ,在调用新函数时,提供任何一个给定的参数序列。
这个函数其实也很重要,只是当时红宝书也没说起不少。
fun.bind(thisArg[, arg1[, 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
欢迎拍砖,有更多的好的例子,欢迎提出,文中有误的地方也欢迎指正。