从面试题分析this

来源:互联网 发布:python编程入门下载 编辑:程序博客网 时间:2024/06/07 05:07

            这几天工作贼忙~项目页面逻辑需要大的整改,一直忙到没时间看一些其他东西(回家倒头就想睡觉),好不容易抽了一个早上的时间,马上来学习一下this整改关键字。(毕竟这个是js中的基础中的基础,也是重难点)

            OK废话不多说,还是老规矩,先上一个面试题,找了蛮久的,而且有个人的解释特别清晰(而且还涉及到了作用域和闭包),我就直接贴一下他的解释,然后自己再补充一点其他的知识点,扩展一下。


var number=2;var obj={   number:4,   fn1:(function(){           var number;           this.number*=2;           number=number*2;           number=3;           return function(){                 var num=this.number;                 this.number*=2;                 console.log(num);                 number*=3;                 alert(number);           }    })(),    db2:function(){        this.number*=2;    }}var fn1=obj.fn1;alert(number);fn1();obj.fn1();alert(window.number);alert(obj.number);
大家有答案了么?


下面是别人的答案,十分的清晰,如果你对this有所了解的话,应该一下就能看明白,如果看不明白,也没关系,可以再看一下我后面的一些总结。

var number=2;var obj={   number:4,   fn1:(function(){ // 匿名函数1           var number;           this.number*=2;// (1)           number=number*2;// (2)           number=3;           return function(){ // 匿名函数(2)                 var num=this.number;                 this.number*=2;                 console.log(num);                 number*=3;                 alert(number);           }    })(),    db2:function(){        this.number*=2;    }}var fn1=obj.fn1; // (3)alert(number);// (4)fn1();// (5)obj.fn1();// (6)alert(window.number);alert(obj.number);•当定义obj的时候执行了匿名函数1,此时处于全局作用域内,因此上下文this是window。执行完语句(1)导致全局变量number的值变为4;执行语句(2)时临时变量number还没有被赋值,所以是NaN,但下一句会将其赋值为3;最后,匿名函数1返回了匿名函数2,因此obj.fn1=匿名函数2。(注意匿名函数2里面会用到临时变量number,老生常谈的闭包)•来到语句(3),这句会把fn1这个变量赋值为obj.fn1,也就是匿名函数2•由于全局变量number已经在语句(1)中变为了4,所以语句(4)弹出的对话框结果为4•语句(5)执行的是fn1(),它与执行obj.fn1()的区别是两者this不一样。前者为null,而后者this为obj。但是又由于JS规定,this为null时相当于全局对象window,所以这句代码执行时函数的this为window。在匿名函数2里会将全局变量number更新为8,同时将匿名函数1中被闭包的临时变量number更新为9•语句(6)的效果在上面已经分析过了,this是obj,所以obj.number更新为8,闭包的number更新为27


下面就是我自己的总结:


如果我们看完题目和答案还是一头雾水的话就可以先”预习“一下,然后再回过头去看题目。

__________________________________________________________________________________________________________________

1.谁调用这个函数或方法,this关键字就指向谁。

2.在JS中,一个函数中的this只有到了执行的时候才能确定是什么,例如函数声明的时候里面的this其实是null,js规定为null的时候其实就是window(浏览器的环境下)。在执行的时候如果这个函数是某个实例对象下的一个 方法则指向这个实例对象,否则也是window。


3.函数的调用方式:普通函数调用,作为方法来调用,作为构造函数来调用,使用apply/call方法来调用。

*普通函数的话很简单,就是相当于这样去调用:

/****************************************************/

var fun(){

  console.log(this); //[object Window]

 }

fun();

这里的其实把fun当作一个全局函数去调用,它的对象是window,所以根据我们第2个知识点,它声明的时候调用它的对象是window,调用的时候也是window,所以它这里的this总是window。


*作为方法来使用:

/******************/

var o={

  fun:function(){

   console.log(this);

  }

}

o.fun();// [object Object]

这里使用的时候是o去调用fun这个函数,所以this指向的就是o这个对象。

如果我这里在上面这个题目上做一个变形:

 var a=o.fun;
  a(); //[object Window]

没错,这里使用的时候a其实是window的一个属性,当去调用a()的时候,就相当于window去调用,this就又指向了window。


*作为构造函数来使用:

/************************/

function Fun(){

  this.fun=function(){

    console.log(this);

 }

}

var o=new Fun();

o.fun(); // [ object Object]

这里运用到了new,我以前在原型的面试题中说过,new这个过程的最后一步就是把this指向实例出来的对象,也就是我这里的o。


*使用apply/call方法来调用,其实函数也是对象,call和apply其实就是函数原型上的一种方法,它能调用这个函数。

/****************/

function fun(){

  console.log(this);

 }

fun.call();

fun.apply();

这两种方式都是调用这个函数,其实函数的调用都可以看作是用call和apply来执行,用.apply( )或者.call()来代替我们的( ).

总结起来就是fun( ) --> fun.call( );

                      obj.fun( ) --> obj.fun.call(obj);


4.我们其实可以通过call,apply,bind(这个是js的方法,不同于jq中的bind)方法来改变我们this的所指向对象。

首先说一下call和apply:

(上面的call和apply参数的问题,第一个参数如果传了,那么这个函数里面的this就指向这个传进来的第一个参数,如果不传则是window,后面的参数就是这个函数需要的参数)


call与apply是函数都具有的一个方式,其作用是可以改变其this的指向,其调用方式有所不同。

call和apply第一个参数都一样,不过apply后面的参数以数组形式传递建议使用。




我们来看一下这个题目:

  

var x = 10; var obj = {       x: 20,       f: function(){         console.log(this.x); var foo = function(){           console.log("foo:"+this.x); } foo();    }   };obj.f();

执行结果是 20 ,10

为什么呢?因为foo是var 出来的一个变量,它不是从属于obj,其实是window的属性,所以它里面的this是指向window的,但是我们这里可以用call来把它的this来改变一下。

foo.call( obj )

这样之后结果就变成了20,20   (这个题目是不是跟面试题有异曲同工之妙呢?)


介绍了call的方法,我们知道了它可以调用函数,可以改变this指向,那么我们就可以让B对象去调用A对象的方法了。

可以看下面这个例子:

function FruitA(n1,n2){        this.n1=n1;        this.n2=n2;        this.change=function(x,y){            this.n1=x;            this.n2=y;        }    }        var fruitA=new FruitA("cheery","banana");    var FruitB={        n1:"apple",        n2:"orange"    };    fruitA.change.call(FruitB,"pear","peach");    console.log(FruitB.n1); //输出 pear    console.log(FruitB.n2);// 输出 peach


我们这里可以看到对象FruitB是没有change的方法的,它是存在于FruitA中,我们这里就是实例化了一个FruitA的对象,然后利用call去改变this指向,指向了FruitB,然后去改变FruitB中的n1和n2的值。


上面说完了call和apply,这里要说一下bind,!!!这个bind是ES5出来的函数(IE8及一下是不支持的),并不是JQ的bind,所以JQ现在都提倡不用bind,用on了。

大家可以看看这个博客:http://www.cnblogs.com/iyangyuan/p/4493322.html









0 0
原创粉丝点击