参考视频:http://www.imooc.com/video/6430node
JavaScript中的this比较灵活,也是让不少初学者摸不到头脑,那么根据在不一样的环境下,在同一个函数,不一样的调用方式下,那么这个this也有多是不一样的。windows
咱们先来看,全局做用于下的this。数组
全局的this(浏览器)浏览器
console.log(this.document===documet);//trueapp
console.log(this===window);//trueide
this.a=37;函数
console.log(window.a);//37this
全局做用域下的this通常指的是全局对象,在浏览器里面通常指的是windows。好比上面的this.document就是window.document. 这里的this就至关于window,因此this=window.spa
so,this.a=window.a。prototype
通常函数的this(浏览器)
function f1(){
return this;
}
f1()===window;//true,global object
好比咱们用这样的通常函数声明和通常表达式,而后咱们直接去调用这样的函数的话,那么这里面的this仍然指向全局变量,那么在浏览器里面就是window,那么在node.js里面呢,就是global对象。
function f2(){
"use strict"//ee strict mode
return this;
}
f2()===undefined;//true
咱们须要注意的一点就是严格模式下呢,通常函数调用的this会指向这个undefined.
咱们更常见的做为对象方法的函数的this:
var o={
prop:37,
f:function(){
return this.prop;
}
};
console.log(o.f());//logs 37
是将this做为对象方法去用的时候,咱们知道,函数呢,若是做为一个对象的属性,好比咱们这建立的自变量o,那么o里面有个属性f,它的值是一个函数对象,那对于这样一个把函数做为一个对象属性值的方式,咱们经常叫作一个对象的方法。那么多为对象方法去调用的时候,好比这里的用o.f()去调用,这种状况的this通常会指向这样一个对象o,这里咱们能够看到o.f()调用之后会返回37,由于this指向了o,因此至关于o.prop,因此最终的结果是37。
var o={prop:37};
function independent(){
return this.prop;
}
o.f=independent;
console.log(o.f());//logs 37
那么这里面,咱们不止是必定要定义成函数自变量的对象,好比这里面咱们定义了一个对象o,只有一个属性prop:37;那么这里面咱们有个独立的independent函数,那么这里面的函数,咱们仍然return this.prop,若是我直接去调用independent的话,则this依旧指向window。这里临时建立一个o的属性f(便是o.f)而且指向independent,因此这样再调用console.log(o.f(),则又跟上一条函数同理!
这里面是否是看函数是怎么建立的,而是只要将这个函数做为对象的方法,就像这个o.f()去调用的话,那么,这个this,就会指向这个o.prop。
对象原型链上的this:
var o={f:function(){return this.a+this.b;}};
var p=Object.create(o);
p.a=1;
p.b=4;
console.log(p.f());//5
建立一个对象o里面有属性f,而且函数做为属性的值,咱们经过Object.create建立了一个对象p,而对象P是一个空对象,而且它的原型指向了o,那么p.a=1;p.b=4;这样建立了对象的属性,那么我去调用它原型上方法的时候,this.a和this.b依旧能取到p.a和p.b的值。这里面p的原型才是o,也就是说,调用p.f()的时候调用的时候这个对象原型对象上的o上面的属性f。
get/set方法与this:
function modulus(){
return Math.aqrt(thisre*this.re+this*this.im);
}
var 0={
re:1,
im:-1,
get phase(){
return Math.atan2(this.im,this.re);
}
};
Object.defineProperty(o,'modules',{
get:modulus,enumerable,configurable:ture});
console.log(o.phase,o.modulus);//logs-0.78 14.4142
get/set方法也是相似的,这里用的是一个modules。而后这里咱们去计算this.re和this.im,这里咱们用一个对象o,而且o里面有一个get方法,给这样的属性phase,再用
Object.defineProperty(object, propertyname, descriptor)去定义o的属性,这里咱们一样能够调用o.phase和o.modulus去拿到o的属性,那么modules里面的this依旧会指向o的re和im,咱们也要知道get/set方法里面的this也是会指向它所在的那个对象里面,那么咱们临时动态区别一下O这个对象与建立.modulus的属性也是相似的,那么这一点上,和通常的对象属性做为函数对象也是相似的!
构造器中的this:
function MyClass(){
this.a=37;
}
var o= new MyClass();
console.log(o.a);//37
function C2(){
this.a=37;
return{a:38};
}
o=new C2();
console.log(o.a);//38
若是咱们正常去调用MyClass这个函数的话,this就是指向全局变量window,可是若是用new MyClass来把它做为构造器去调用的话,那么MyClass的this会指向空的对象,而且这个对象会指向原型MyClass.prototype.这里使用了new之后,那么这个this会指向一个原型为MyClass.prototype属性的这样一个空对象,那么这样因为咱们的this.a赋值了37,并且MyClass的返回值默认是this,因此这对象o就会输出37。那么相似的咱们定义了一个函数C2,而后this.a=37,可是return里面的返回的语句是a:38,因此a就再也不是37了,而是38。当咱们使用new来建立这样一个构造器来这样去调用的时候,那么这样的this会指向一个原型为MyClass.prototype这样一个空对象,最后仍是要看返回值,若是你没有写return语句,则默认返回this,若是有return语句返回了一个对象的话,因此会将return的对象做为返回值,因此o.a就是38.
call/apply方法与this:function add(c,d){return this.a+this.b+c+d;}var 0= {a:1,b:3};add.call(,o,5,7);//1+3+5+7=16add.apply(o,[10,20]);//1+3+10+20=34function bar(){console.log(Object,prototype.toString.call(this));}bar.call(7);//"[object Number]"除了不一样的调用方式,每个函数对象也会有方法,能够去修改函数执行时的里面的this,比较常见的就是call/apply。好比我这里面的函数声明add,咱们用this.a和this.b,和参数c和d把这四个数相加起来。咱们是怎么作的呢,咱们是定义一个变量o,里面有两个属性a:1,b:3,而后经过这个对象的的call方法,把第一个参数接受那个关于this的对象,后面是5和7(也就是咱们想添加的参数),也就是c=5,d=7,最终的结果是就1+3+5+7=16。其实call和apply其实没有什么差异,只是call和apply传参的方式不一样,call是直接把参数变量传输进去的,而apply是将参数做为数组的形式传输进去,因此apply的结果是也是1+3+10+20=34,。如今咱们来区分一下状况下用到这个call和apply,好比说,咱们想调用Object,prototype.toString,可是咱们想指定某一个this的时候,来调用一些咱们没法直接调用的一些方法,那么咱们这里去调用bar。call(7),这样就能拿到内部的这样一个标签间接的字符串。bind方法与this:function f(){return this.a;}var g=f.bind({a:"test"});console.log(g());//testvar o={a:37,f:f,g:g};console.log(o.f(),o.g());//37 test除了call/apply还有bind方法,bind方法只能兼容IE9以上版本,咱们定义了一个函数对象f(),而后咱们经过bind的方法,定义了一个a的对象,并把参数值“test”传进去,这样咱们就获得了一个g对象,咱们到下面调用输出的时候,发现已经调用了test这个参数,这样是采用了绑定一次,并重复去调用,仍然实现这种绑定的话,这样会比咱们使用call/apply高效一点。咱们下面又定义了一个函数o,而后把a赋值为37,而后f赋值了f(),g赋值了g(),而后咱们输出的o.f(),o.g()是37,test.这里比较特殊的就是咱们使用了bind方法,即便咱们使用了bind方法,并把新绑定方法做为对象的属性去调用,那么这里依旧会按照以前的绑定去走,因此也就返回这个test