this指向及改变this指向的方法

this的指向在函数定义时是确定不了的,只有在函数执行时才能确定,this最终指向调用它的对象。

this在js中主要有四种用法:

1、作为普通函数使用

2、作为对象方法来使用

3、call和apply

4、作为构造函数来使用

 

1、作为普通函数使用

var name='window';
function s(){
    var name='myself';
    console.log(this.name);//window
}
s();

2、作为对象方法来使用

var name='window';
var obj={
    name:'obj',
    sayName:function(){
        console.log(this.name);
    }
}
obj.sayName();//obj;

这个很简单,this指向自己,所以this.name就用hello;

 

(在全局里面this指向window,在某个对象里面this指向该对象,在闭包里面this指向window)

var user="the Window";
var box={
  user:'the box',
  getThis:function(){
    return this.user;
  },
  getThis2:function(){
    return function (){
      return this.user;
    }
  }
};
alert(this.user);//the Window
alert(box.getThis());//the box
alert(box.getThis2()());//the Window (由于使用了闭包,这里的this指向window)
alert(box.getThis2().call(box));//the box 对象冒充(这里的this指向box对象)

3、call和apply

所有函数对象都有两个方法:apply和call,这两个方法可以让我们构建一个参数数组传递给调用函数,也允许我们改变this值。

使sayName中的this指向b,改变this的指向
var name='window';
var obj={
    name:'obj',
    sayName:function(){
        console.log(this.name);
    }
}
var b={name:'abcd'};
//改变this指向
var newobj=obj.sayName;
newobj();//将this指向全局

newobj.call(b);//abcd   将this指向b   改变this的指向并且执行调用函数

 

4、作为构造函数来使用

function test(){
    this.name=1;
}
var myobj=new test();
console.log(myobj.name);

 

练习题

在执行person1.sayName()时,this指向person1对象

在执行person2.sayName()时,sayName()方法并没有执行,而是将sayName()赋值给fun变量,fun()是普通函数调用模式,this指向window,所以输出全局name

 

 

执行console.log(b.n)时,b对象有自己的属性n值

执行console.log(c.n)时,c对象没有自己的属性n值,会向上查找,找的A对象中的属性n值

 

var getColor=test.getColor相当于把方法函数赋值给全局变量,

故getColor()中的this指向window

 

二、改变this指向的方式

以下属于函数的方法

改变this的指向并且执行调用函数

(1)通过一个对象的方法来定义函数,并用该对象调用方法。

var name='window';
var obj={
    name:'obj',
    sayName:function(){
        console.log(this.name);
    }
}
var b={};
b.x='is o'
b.fun=obj.sayName;
b.fun();

(2)call() 和 apply() 

call()方法存在于Function的原型上,Function.prototype.call(),因此每个函数都可以通过原型链继承下来。

属于函数的方法,只有函数对象可以调用

相同点:两个方法产生的作用是完全一样的,都用来改变当前函数调用的对象。

不同点:调用的参数不同,比较精辟的总结:

foo.call(this,arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)

1.call的使用

call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

 

window.color="red";
var o={
color:"blue"
};
function sayColor(){
console.log(this.color);
}
sayColor();//指向window
sayColor.call(this) ; //指向自己
sayColor.call(window); //red
sayColor.call(o); //blue

解析:最后一个之所以输出的是blue,是因为call()方法的第一个参数指的是在其中运行函数的作用域,所以在sayColor.call(o)中,它把函数的作用域定在了对象o中,所以函数sayColor()中的this.color即为o.color,因此输出的是对象o的color的值bule. 

2.apply()

apply与call的功能几乎一样,第一个参数意义都一样,只是第二个参数有点不同apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,call从第二个参数开始,依次传值给调用函数的参数 

 call、apply与bind的区别:前两个可以自动执行,bind只创建一个新的函数,不会自动执行,需要手动调用。

(3)bind()

bind()会创建一个函数的实例,其this值会被绑定到传给bind()函数的值。如

var color='red';
var o1={
    color:'blue'
};
var o2={
    color:'yellow'
};
function sayColor(){
    console.log(this.color);
}
//call()自动执行
sayColor.call(o1);//blue

//bind()需手动执行
var say=sayColor.bind(o2);
say();//yellow

 

bind()除了改变函数this指向的功能,还有柯里化的功能,即把一个函数拆成多个单元。

柯里化是指这样一个函数,他接收函数A作为参数,运行后能够返回一个新的函数,并且这个新的函数能够处理函数A的剩余参数。

function add(a,b,c){
    console.log(a+b+c);
}

var func=add.bind(undefined,100);//第一个参数为undefined、null指不需要改变this
func(1,2);//103    绑定时传入一个参数100,在调用时传入第二个和第三个参数

var func2=func.bind(undefined,200);
func2(10);//310      之前绑定a=100,所以200绑定到b上

为什么要使用柯里化呢?

比如需要写一个获取一套配置的函数,不同页面下的配置可能是不同的,在同一模块下,其中有些参数是相同的,不同页面获取时只需要传入otherOptions即可,把一个函数拆分成子函数,使代码重用。

bind与new

function foo(){
    this.b=100;
    return this.a;
}
var func=foo.bind({a:1});
console.log(func());//1
console.log(new func());//{b:100}

使用new 函数时,函数中的return除非是对象,否则会把this作为返回值,并且this会被初始化一个默认的空对象,对象的原型就是foo.prototype,所以new一个对象时,即使方法以bind了一个对象,this仍指向原函数。

 

手写bind()函数   柯里化

结合     (this与指向对象颜色相同)

function foo(){
    this.b=100;
    return this.a;
}
var func=foo.bind({a:1});
console.log(func());//1
console.log(new func());//{b:100}

 

考虑到构造函数的情况:

Function.prototype.bind=function(context){//context指bind函数的第一个参数var args=Array.prototype.slice.call(arguments,1);
    var self=this;//this仍然指调用bind()的函数对象
    var fun=function(){};
    var fBound=function(){
        var innerArgs=Array.prototype.slice.call(arguments);//获取内部函数的传入的所有参数
        var outerArgs=args.concat(innerArgs);
        return self.apply(this instanceof fun?this:context,outerArgs);
    };//self就是相当于调用的foo()   该处this指func()执行时的this即window,所以fun=oThis
          //当new func()时this指向foo(),所以this instanceof fun为true
         //Array.prototype.slice.call(arguments)是后面传的参数b和c,用拼接的方式获取a,b,c完整的参数
    fun.prototype=this.prototype;
    fBound.prototype=new fun();//以上两句使fBound是fun的实例
    return fBound;//fBound作为返回值,相当于生成的函数对象func
};

 知识点:

(1) Array.prototype.slice.call(arguments)能够将类数组对象转换为数组。

 (2)Array.prototype.slice.call(arguments,1);//截取,获取外部函数的第一个参数之后的所有参数,参数1表示被返回的数组包含从第二个参数开始的所有参数,即去除函数自己的方法名

(3)this instanceof fun?this:context         //这段代码判断通过bind方法绑定得到的函数,是直接调用还是用构造函数通过new来调用。

(4)通过设置一个中转构造函数fun,使绑定后的函数与调用bind()的函数处于同一原型链上,用new操作符调用绑定后的函数,返回的对象也能正常使用instanceof。

转载于:https://www.cnblogs.com/xiaoan0705/p/8651879.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值