zoukankan      html  css  js  c++  java
  • js中this的指向问题

    this指向性问题在开发过程中,可以说是时时刻刻都在,自己也知道一些this指向的区别,但是并没有细致的研究过,今天看到https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this里面的解释很详细,摘录一些留着自己以后复习复习。

    函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。

    一、在全局环境中

    在全局执行环境中(在任何函数体外部),this都是指向全局对象。在浏览器中,window对象即是全局对象:

    console.log(this); //Window
    var a = 1;
    console.log(window.a);  //1
    this.b = 3;
    console.log(b); // 3
    console.log(window.b) //3

    二、在函数环境中

      在函数内容,this指向取决于函数调用的方式:

    function f(){
    "use strict"; //使用严格模式
    console.log(this); } f(); // window ;使用严格模式时,输出undefined
    这里我理解为实际调用函数的是浏览器的window.f();实际并非如果,在严格模式下,返回值:false,因为f是被直接调用的,而不是作为对象的属性或方法调用的(如 window.f())。浏览器可能在支持严格模式时没有正确实现这个功能,于是它们错误地返回了window对象。
    this指向如何发生改变?
    1、一般想到的是call和apply方法:将一个对象作为call或者apply的第一个参数,this将会被绑定到这个参数对象上
    var obj = {parent:'男'};
    var parent = '28';
    function child(obj){
        console.log(this.parent);
    }
    child(); // 28  
    child.call(obj); //
    child.apply(obj); //

    2、bind方法,调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,不管函数是怎样调用的。

    function f(){
      return this.a;
    }
    var g = f.bind({a:"js"});
    console.log(g()); // js
    
    var h = g.bind({a:'html'}); // this已经被绑定bind的第一个参数,不会重复绑定,输出的值还是js
    console.log(h()); // js
    
    var o = {a:css, f:f, g:g, h:h};
    console.log(o.f(), o.g(), o.h()); // css, js, js

    3、箭头函数

    官方有解释,箭头函数引入的其中一个原因,就是其不绑定this;在箭头函数中,箭头函数的this被设置为封闭的词法环境的,换句话说,箭头函数中的this取决于该函数被创建时的环境。

    var objProject = this;
    var foo = (() => this);
    console.log(foo());  // window
    console.log(objProject);  // window
    console.log(foo() === objProject ); // true
    // 作为对象的一个方法调用
    var obj = {foo: foo};
    console.log(obj.foo() === objProject ); // true
    // 尝试使用call来设定this
    console.log(foo.call(obj) === objProject ); // true
    // 尝试使用bind来设定this
    foo = foo.bind(obj);
    console.log(foo() === objProject ); // true

    4、作为对象的方法调用时

    当函数作为对象的方法被调用时,this指向调用的该函数的对象:

    var obj = {
      a: 37,
      fn: function() {
        return this.a;
      }
    };
    console.log(obj.fn());  // 37

    请注意,这样的行为,根本不受函数定义方式或位置的影响。在前面的例子中,我们在定义对象obj的同时,将函数内联定义为成员 fn。但是,我们也可以先定义函数,然后再将其附属到obj.fn。这样做会导致相同的行为:

    var obj = {a: 47};
    function independent() {
      return this.a;
    }
    obj.fn = independent;
    console.log(obj);  //{a:47,fn:f}
    console.log(obj.fn()); //  47

    对于在对象原型链上某处定义的方法,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

    在这个例子中,对象p没有属于它自己的f属性,它的f属性继承自它的原型。虽然在对 f 的查找过程中,最终是在 o 中找到 f 属性的,这并没有关系;查找过程首先从 p.f 的引用开始,所以函数中的 this 指向p。也就是说,因为f是作为p的方法调用的,所以它的this指向了p

    5、作为构造函数

    当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

    虽然构造器返回的默认值是this所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回this对象)。

    function C(){
      this.a = 37;
    }
    
    var o = new C();
    console.log(o.a); //  37
    function C2(){
      this.a = 37;
      return {a:38};
    }
    o = new C2();
    console.log(o.a); //  38,手动设置了返回对象

    6、作为DOM事件处理函数

    当函数被用作事件处理函数时,它的this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)。

    // 被调用时,将关联的元素变成蓝色
    function bluify(e){
      console.log(this === e.currentTarget); // 总是 true
      // 当 currentTarget 和 target 是同一个对象时为 true
      console.log(this === e.target);        
      this.style.backgroundColor = '#A5D9F3';
    }
    // 获取文档中的所有元素的列表
    var elements = document.getElementsByTagName('*');
    // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
    for(var i=0 ; i<elements.length ; i++){
      elements[i].addEventListener('click', bluify, false);
    }

    关于this问题的一道面试题:

    var baz = 0;
    let foo = {
        bar:function() {
            console.log(this,this.baz); 
            return this.baz;
        },
        baz:1
    };
    let foo2 = {
        baz:2
    };
    
    let a = foo.bar();  //作为对象的方法调用,this指向调用函数的对象,即foo
    let b = foo.bar.call(foo2); //使用call方法将this绑定到第一个参数对象向,此时,this指向foo2
    let fn = foo.bar;
    console.log(fn);
    let c = fn(); //let fn创建的对象,此时,fn = function(){...},此时函数执行时,默认指向全局window对象
    let d;
    (function test(){
      d = arguments[0]()
    })(foo.bar);   // arguments.callee包括了一个函数的引用去创建一个arguments对象,它能让一个匿名函数很方便的指向本身,即此时this指向arguments类数组对象
    console.log(a,b,c,d);

    结果如下:

  • 相关阅读:
    [Caffe] ubuntu14.04下使用OpenBLAS加速Caffe
    [CUDA] ubuntu14.04+cuda7.5下安装cudnn7.0
    ubuntu下virtualenv的复制
    SIFT特征学习笔记
    ubuntu14.04+opencv 3.0+python2.7安装及测试
    django之ORM
    django之路由(url)
    性能调优之MySQL篇四:MySQL配置定位以及优化
    性能调优之MySQL篇三:MySQL配置定位以及优化
    性能调优之MySQL篇二:MySQL配置文件My.ini配置文件优化
  • 原文地址:https://www.cnblogs.com/layaling/p/10650366.html
Copyright © 2011-2022 走看看