zoukankan      html  css  js  c++  java
  • javascript当中的this详解

    总结this的3个规则:

    1. this是调用上下文,上下文被创建或者初始化时才确定
    2. 非严格模式:this是全局对象;严格模式:this是undefined
    3. 函数调用

        a. 以函数形式调用的函数通常不使用this关键字,非严格模式下函数调用模式的this就是全局对象。

        b. 以方法形式调用的函数的this指的是当前调用方法的对象

        c. 以构造函数形式调用的函数的this指的是被构造的对象,具体操作为:

          i. 创建一个新对象

          ii. 将构造函数的作用域赋给新对象(因此构造函数中的this就指向这个新对象)

          iii. 执行构造函数的代码(为这个新对象添加属性,这个时候this才确定下来就是该对象)

          iv. 返回新对象

          v. 另外要注意的是,构造函数通常不使用return关键字,如果使用,则调用表达式的值就是return的这个对象,如果使用却没有指定返回值,或者返回一个原始值,那么就忽略返回        值,同时使用构造出来的新对象作为返回结果。

      4. this是一个关键字,js的语法不允许给this赋值,关键字this没有作用域的限制,嵌套的函数不会从调用它的函数中继承this。即:如果嵌套函数作为方法调用,其this的值指向调用它的对象(与规则3相符合)

             如果嵌套函数作为函数调用,其this的值不是全局对象(非严格模式)就是undefined(严格模式)。(与规则2、3符合)

    例子:嵌套函数访问外部函数的this(来自《javascript权威指南》P171)

    var o={                                    //对象o
      m:function(){                          //对象中的方法m()
      var self=this;                         //将this的值保存至一个变量中
      console.log(this===o);                 //输出true,this就是这个对象
       f();                                  //调用辅助函数f()(此时调用外部函数的m()时此处的f()调用嵌套函数就属于函数调用了)
     
      function f(){                          //定义一个嵌套函数
        console.log(this===o);         //"false":this的值是全局对象或者undefined;
        console.log(self===o);        //"true":self指外部函数的this值
      }
     
    }

      5. 构造函数的原型模式中的this

       如果要在基本包装类型String添加了一个名为startsWith()的方法。 

    String.prototype.startsWith=function(text){
      return this.indexOf(text)==0;
    }
     
    var msg="hello world";
    alert(msg.startsWith("Hello"));   //true

    这里的原型函数中的this也是指向调用者的,要知道prototype中的这些方法和属性是所有实例对象所共享的,也就是说当新创建的对象msg以方法调用模式调用startsWith()方法,虽然在实例中没有找到这个方法,但在原型对象中找到了这个方法,故返回的就是这个方法的值,注意,在原型中查找值的过程是一次过程。

      6. 匿名函数中的this

      匿名函数属于函数表达式,不能变量提升,函数表达式必须等到js引擎执行到它所在行时,才会从上而下一行一行地解析,匿名函数的执行环境具有全局性,因此其this对象通常指向window,来看( function(){…} )()和( function (){…} () )这两种立即执行函数的写法,要知道在函数体后面加括号就能立即调用,则这个函数必须是函数表达式,不能是函数声明。

      这样的写法有什么用呢?

    javascript中没用私有作用域的概念,如果在多人开发的项目上,你在全局或局部作用域中声明了一些变量,可能会被其他人不小心用同名的变量给覆盖掉,根据javascript函数作用域链的特性,可以使用这种技术可以模仿一个私有作用域,用匿名函数作为一个“容器”,“容器”内部可以访问外部的变量,而外部环境不能访问“容器”内部的变量,所以( function(){…} )()内部定义的变量不会和外部的变量发生冲突,俗称“匿名包裹器”或“命名空间”。

    例子:

    • 箭头函数中的this
    let name='windows'; 
    let obj={
      name:'windows',
      stack: () => {
        console.log(this.name);   //undefine
      }
    }
    console.log(obj.stack());     //undefine

    说明:箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或者new.target。这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。箭头函数不会创建自己的this,它只会从作用链的上一层继承this。

    function Stack() { 
      this.age = 0; 
      setInterval(() => { 
        this.age++; // this正确地指向Stack对象 
      }, 1000); 
    } 
    var p = new Stack(); 
    console.log(p.age);

    箭头函数不能用作构造器,和new一起会抛出错误

    let Foo = () => {};
    let foo = new Foo(); // TypeError: Foo is not a constructor
     
    let Stack=()=> {
      let name='outside';
      class Stack{
        constructor(){
          this.name=name;
        }
      }
      return Stack;
    };
    let b=new Stack();
    console.log(b.name);//Stack is not a constructor
     
    let Stack = () => {
      let name = 'outside';
      console.log(this);
      class Stack {
        constructor() {
          this.name = name;
        }
      }
      return Stack;
    };
    console.log(new Stack().name); //Stack is not a constructor

    箭头函数没有prototype属性

    let Foo = () => {};
    console.log(Foo.prototype); // undefined
    • 箭头函数用于闭包
    let Stack = () => {
      let name = 'outside';
      console.log(this);//Window
      class Stack {
        constructor() {
          //this.name = 'inside';
          this.name = name;
        }
      }
      return new Stack();
    };
    console.log(Stack().name);//outside
    let Stack = () => {
      let name = 'outside';
      console.log(this);//Window
      class Stack {
        constructor() {
          this.name = 'inside';
        }
      }
      return Stack;
    };
    console.log(Stack().name);//Stack
    • 匿名函数用于闭包
    let Stack = function() {
      let name = 'outside';
      console.log(this);//Window
      class Stack {
        constructor() {
          this.name = name;
        }
      }
      return Stack;
    }();
    let b = new Stack();
    console.log(b.name);//outside
     
    let Stack = function() {
      let name = 'outside';
      console.log(this);//Window
      class Stack {
        constructor() {
          this.name = name;
        }
      }
      return Stack;
    };
    //let b = new Stack();
    let b = Stack();
    let a=new b();
    console.log(a.name);//outside
  • 相关阅读:
    小问题收集
    JSON.NET与LINQ序列化示例教程
    前台页面中json和字符串相互转化
    jQuery Validate (1)
    jQuery Validate (摘自官网)
    SQL基础(八)-- sql左右连接中的on and 和 on where 的区别
    SQL基础(七)--or和in的使用
    SQL基础(六)--RaiseError的用法
    C#基础(三)--Sort排序
    C#中Equals和==的区别 (面试官经常会问到)
  • 原文地址:https://www.cnblogs.com/baotong-9396/p/9959045.html
Copyright © 2011-2022 走看看