js this


原文链接: js this

js常见的var that = this的用法

this是Javascript语言的一个关键字。它代表函数运行时,自动生成的一个内部对象,this代表的是当前对象,只能在函数内部使用
var that=this 就是将当前的this对象复制一份到that变量中

$('#content').click(function(){
    //this是被点击的 #content
    var that = this;
    $('.content').each(function(){
    //this是.content循环中当前的对象
    //that仍然是刚才被点击的#content
    });
});

可以看到,this对象在程序中随时会改变,而var that=this之后,that没改变之前仍然是指向当时的this,这样就不会出现找不到原来的对象

彻底弄懂js中的this指向

方法改写:
· foo() ---> foo.call(window)
· obj.foo() --> obj.foo.call(obj)

js中的this指向十分重要,了解js中this指向是每一个学习js的人必学的知识点,今天没事,正好总结了js中this的常见用法,喜欢的可以看看:

1.全局作用域或者普通函数中this指向全局对象window。

//直接打印
console.log(this) //window

//function声明函数
function bar () {console.log(this)}
bar() //window

//function声明函数赋给变量
var bar = function () {console.log(this)}
bar() //window

//自执行函数
(function () {console.log(this)})(); //window

2.方法调用中谁调用this指向谁

//对象方法调用
var person = {
    run: function () {console.log(this)}
}
person.run() // person

//事件绑定
var btn = document.querySelector("button")
btn.onclick = function () {
    console.log(this) // btn
}
//事件监听
var btn = document.querySelector("button")
btn.addEventListener('click', function () {
   console.log(this) //btn
})

//jquery的ajax
 $.ajax({
    self: this,
    type:"get",
    url: url,
    async:true,
    success: function (res) {
        console.log(this) // this指向传入$.ajxa()中的对象
        console.log(self) // window
    }
   });
 //这里说明以下,将代码简写为$.ajax(obj) ,this指向obj,在obj中this指向window,因为在在success方法中,独享obj调用自己,所以this指向obj

3.在构造函数或者构造函数原型对象中this指向构造函数的实例

//不使用new指向window
function Person (name) {
    console.log(this) // window
    this.name = name;
}
Person('inwe')
//使用new
function Person (name) {
      this.name = name
      console.log(this) //people
      self = this
  }
  var people = new Person('iwen')
  console.log(self === people) //true
//这里new改变了this指向,将this由window指向Person的实例对象people

How to understand this on javascript

说到this,就不得不提到function,相信看过其它类似文章的同学也知道,正是由于调用function的对象不同,才导致了this的指向不同。所以以前老是去记忆每种调用function的情况所对应的this,因为情况有限而且很少,所以这当然是可行的——对于聪明人来说。所以我不得不思考另外一些方式来让我记住。

那么首先我们需要明确的一个事情是:function 也是对象

同时我们还需要明确的一个事情是:function 执行时是在某个特定的上下文中执行的。那什么是上下文呢?打个比方,比如你练会了辟邪剑谱,那这时候你的掌门让你用辟邪剑谱砍人。如果仅仅是这样的话,你是没法完成这个任务的,因为你必须得知道要砍谁吧,其次去哪儿砍吧,那么是个地下通道还是一望无尽的大草原,要是地下通道你走路都困难,还怎么用辟邪剑谱呢对吧。这就是上下文,函数执行时它也需要一些额外的信息来支撑它的运行。那么既然function是对象的话,就会有方法。而function中最核心的方法是call方法。因此我们就从这儿入手。

call方法

先来看一下如何使用call方法:

function say(content) {
    console.log("From " + this + ": Hello "+ content);
}    
say.call("Bob", "World"); //==> From Bob: Hello World

· Step1: 把第二个到最后一个参数作为函数执行时要传入的参数
· Step2: 把函数执行时的 this 指向第一个参数
· Step3: 在上面这个特殊的上下文中执行函数

上面例子中,我们通过call方法,让say函数执行时的this指向"Bob",然后把"World"作为参数传进去,所以输出结果是可以预见的。

js执行函数时会默认完成以上的步骤,你可以把直接调用函数理解为一种语法糖
比如

function say(msg) {
    console.log(msg);
}
say("Hello world"); //以下等价 
say.call(window, "Hello world");

以上可以把say("Hello world")看做是say.call(window,"Hello world")的语法糖。
这个结论非常关键
所以以后每次看见functionName(xxx)的时候,你需要马上在脑海中把它替换为functionName.call(window,xxxx),这对你理解this的指向非常重要。
不过也有例外,在ES5的strict mode中call的第一个参数不是window而是undefined。之后的例子我假设总是不在strictmode下,但你需要记住strictmode有一点儿不同。
匿名函数来说,上面的结论也是成立的

(function(name) {
    //...
})("aa");
//等价于
(function(name) {
    //...
}).call(window, "aa");

函数作为对象的方法被调用

直接来看代码:

    var person = {
        name : "caibirdme",
        say : function(time) {
            console.log(this.name + "has been running for over "+ time+ " minutes");
        }
    };
    person.say(30); //==> caibirdme has been running for over 30 minutes
    //等价于
    person.say.call(person, 30); // the same

你会发现这里call的第一个参数是person而不是window。
当你明白了这两点,下意识地把函数调用翻译成foo.call()的形式,明确call的第一个参数,那基本上this的问题就难不住你了。

还是来举几个例子吧
例一:

function hello(thing) {  
  console.log(this + " says hello " + thing);
}
 
person = { name: "caibirdme" }  
person.hello = hello;
 
person.hello("world") // 相当于执行 person.hello.call(person, "world")
//caibirdme says hello world
hello("world") // 相当于执行 hello.call(window, "world") 
//[object DOMWindow]world

例二:

var obj = {
    x: 20,
    f: function(){ console.log(this.x); }
};
 
obj.f(); // obj.f.call(obj)
//==> 20
obj.innerobj = {
    x: 30,
    f: function(){ console.log(this.x); }
}
 
obj.innerobj.f(); // obj.innerobj.f.call(obj.innerobj)
// ==> 30

例三:函数内部 this 指向 window 对象

var x = 10;
var obj = {
    x: 20,
    f: function(){
        console.log(this.x); //this equals obj
                // ==> 20
        var foo = function(){ 
                    console.log(this.x);
                 }
        foo();  // foo.call(window)
                //foo中this被指定为window,所以==> 10
    }
};
 
obj.f();  // obj.f.call(obj)
// ==> 20 10

由例三引出一个非常common的问题,如果我想让foo输出20怎么办?这时候需要用到一点小技巧
例四: 保存函数内部 this 到 that

var x = 10;
var obj = {
    x: 20,
    f: function(){
        console.log(this.x);
        var that = this; //使用that保留下当前函数执行上下文的this
        var foo = function(){ console.log(that.x); } //此时foo函数中的this仍然指向window,但我们使用that取得obj
        foo(); // foo.call(window)
    }
};
 
obj.f(); // 等价于 ==> obj.f.call(obj)

// ==> 20 20
再来一个稍微难一点点的(但其实用call替换法一点儿也不难)
例五:

var x = 10;
var obj = {
    x: 20,
    f: function(){ console.log(this.x); }
};
 
obj.f(); // obj.f.call(obj)
// ==> 20
 
var fOut = obj.f;
fOut(); // fOut.call(window)
//==> 10
 
var obj2 = {
    x: 30,
    f: obj.f
}
 
obj2.f(); // obj2.f.call(obj2)
//==> 30

例五有些同学会可能出错的原因,是没有明确我上面说的:
this是在执行是才会被确认的
他可能会认为说obj.f那个函数定义在obj里面,那this就该指向obj。如果看完这篇文章你还这么想的话,我会觉得我的表达水平太失败了……

构造函数中的this

先看一段代码:

    func person(name) {
        this.name = name;
    }
    var caibirdme = new person("deen");
    // caibirdme.name == deen

我上面也说了,函数在用作构造函数时同样可以用call方法去代替,那这里怎么代替呢?
这里你又需要明确一点:
new constrcut()是一种创建对象的语法糖
它等价于

    function person(name) {
       this.name = name;  //为什么这里的 this 会指向 new 出来的对象呢?
    }
    var foo = new person("deen");
    //通过new创建了一个对象 

    //new是一种语法糖,new person **等价于**
    var foo = (function(name) {
        var _newObj = {
            constructor : person,
            __proto__ : person.prototype,
        };
        _newObj.constructor(name); // _newObj.constructor.call(_newObj, name)
        return _newObj;
    })();

So you can see …… 为什么new的时候this就指向新的对象了吧?

通过我这篇文章,我希望学会通过把一个函数调用替换成funcName.call的形式,从而理解运行时上下文中this到底指向谁。总结来说就是下面两个等价变形:

· foo() ---> foo.call(window)
· obj.foo() --> obj.foo.call(obj)

只要理解以上两个变形,this就不再是问题啦!!希望我的这种方法对各位同学认识this有所帮助,不要再像我曾经一样掉入this的坑中,相关面试题也不再怕怕啦,哈哈。如果还有问题的话,欢迎下面留言。

学会JS的this这一篇就够了,根本不用记_慕课手记

`