【你不知道的JS】 关于this的详解

【你不知道的JS】–> 关于this的详解

–1--首先我们要思考一个问题,为什么要使用this?

function identify(){
    return this.name.toUpperCase();
}
function speak(){
    var greeting = "Hello,I'm" + identify.call(this);
    console.log(greeting);
}
var me = {
    name:"kyle"
}
console.log(identify.call(me));  //KYLE
speak(me);   //Hello,I'm KYLe.

这段代码可以在不同的上下文对象(me)中重复使用两个函数,不用针对每个对象编写不同的函数。
如果不使用this的话,那就需要给identify()和speak()显示的传入一个上下文对象(context)。

function identify(context){
    return this.name.toUpperCase();
}
function speak(context){
    var greeting = "Hello,I'm" + identify.call(context);
    console.log(greeting);
}
var me = {
    name:"kyle"
}
console.log(identify.call(me));  //KYLE
speak(me);   //Hello,I'm KYLe.

–2--作为一个初学者,我对this也有很浅的理解,很多时候把2this英语话的想当然当作函数本身了,那么我们一起来分析一下。

function foo(num){
    console.log("foo:" + num);
    this.count++;
}
foo.count = 0;
for(var i = 0;i < 10;i ++)
{
    if(i > 7){
        foo(i);
    }
}
//   foo:8
//   foo:9

那么foo.count被调用了几次呢?

console.log(foo.count);  //0

显然foo(…)被调用了两次,但是foo.count依旧是0,所以this指向自身的理解大错特错了。
(那么当增加的count和预期的不一样时,增加的是哪个count?实际上这段代码创建了一个全局变量count)
假如我放弃this,来使用词法作用域解决问题呢?
答案当然是ok的。

function foo(num){
    console.log("foo:" + num);
    date.count++;
}
var date = {
    count:0
}
for(var i = 0;i < 10;i ++)
{
    if(i > 7){
        foo(i);
    }
}
console.log(date.count);  //2

还可以使用call()来解决问题:

function foo(num){
    console.log("foo:" + num);
    this.count++;
}
 foo.count = 0;
for(var i = 0;i < 10;i ++)
{
    if(i > 7){
        foo.call(foo,i);
    }
}
console.log(foo.count);  //2

call在这里显示强制的将this指向改变从而达到目标效果。
–3--.那么this的指向到底怎么看?
我们需要了解一些this的绑定规则。
①:默认绑定:

function foo(){
    console.log(this.a)
}
var a = 9;
foo();  // 9

因为在这里foo是直接使用不带任何修饰的函数进行调用的,因此只能使用默认绑定,不能使用其他规则。
在这里this直接指向全局变量a。
加入在严格模式下:
this将会绑定到undefined。

function foo(){
    "use strict"
    console.log(this.a)
}
var a = 9;
foo();  // a not undefined of foo

②隐式绑定

function foo(){
    console.log(this.a)
}
var obj = {
    a:2,
    foo:foo
}
obj.foo();  //2

隐式绑定也会存在问题—即隐式绑定的函数会丢失绑定对象:

    function foo(){
        console.log(this.a)
    }
    var obj = {
        a:2,
        foo:foo
    }
    var bar = obj.foo;
    var a = 3;
    bar();  
     //bar 是对obj.foo的一个引用,但实际上它绑定的是foo函数本身。 默认绑定this  -->全局的a.

③显示绑定(call(),apply())
同于①中的例子一样,显示绑定会强制改变this指向(也叫做硬绑定):

   function foo(){
        console.log(this.a)
    }
    var obj = {
        a:2
    }
    var bar = function(){
        foo.call(obj)
    }
    var a = 3;
    bar();  //  2     硬绑定的bar不会再修改他的this

类如下面常用的一个封装函数,实现特定的功能:

 function foo(something){
        console.log( this.a, something);
        return this.a + something;
    }
    var obj = {
        a:2
    }
    var bar = function(){
        return foo.apply( obj, arguments);
    };
    var b = bar(3);   // 2 3
    console.log(b);   //5 

重点来了:由于硬绑定是一种非常常用的模式,所以ES5提供了内置方法Function.prototype.bind,用法如下:

foo.__proto__ == Function.prototype   //true
 function foo(something){
        console.log( this.a, something)
        return this.a + something;
    }
    var obj = {
        a:2
    }
    var bar = foo.bind(obj);
    var b = bar(3);  //2 3
    console.log(b)  //5

④new绑定
我们知道在使用构造函数的时候,使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1.常见或者是说构造一个全新的对象。
2.这个新对象会被执行【prototye】连接。
3.这个相信对象会绑定到函数调用的this。
4.这个函数如果没有其他返回对象,最终自动返回这个新对象。

看了这么多,到底是什么意思呢?
举个栗子:

function foo(a){
    this.a = a;
}
var bar = new foo(2);
console.log(bar.a);  //  2

发生的过程如下:

1.var obj = {};
2.obj.__proto__ == foo.prototype;
3.foo.call(bar);  this指向改变,  this  --> bar
4.return obj

4.如何去判断this指向?
上述四种形式的绑定是有优先级顺序的,即new绑定>显示绑定>隐式绑定>默认绑定。(具体可参考(你所不知道的JS上卷p92)
那么根据绑定的优先级我们可以来确定this的指向:
1.函数是否在new中调用(new 绑定)? 如果是的话this绑定的是新创建的对象:

var bar = new foo()  //  this -- >bar

2.函数是否通过call()和apply()(显示绑定,或者硬绑定)调用?如果是的话,this绑定的是指定的对象。

var bar = foo.call(obj)   //this --?obj

3.函数是否在上下文中调用(隐式绑定)?如果是的话,this绑定在那个上下文的对象上。

var bar = obj.foo()  //this -->obj

4.如果都不是的话,使用默认绑定。在严格模式下绑定到undefined,否则绑定到全局对象上。

var bar = foo();

一些自己学习内容的总结。 不够深奥和详细请求见谅,哈哈哈。 2019-6-17

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值