JavaScript 구문 분석--키워드 this

이 글은 금창조의 길을 시작하는 '신인창조식' 행사에 참여하게 되었습니다.

자바스크립트에서 this 라는 키워드는 많은 주목을 받았고 높은 위상을 가지고 있습니다. 오늘의 주인공인 이것으로, 이 글은 (1) 이것의 구속력 있는 규칙, (2) 이것을 가리키는 것, (3) 이것의 지시를 바꾸는 것부터 이것을 심도 있게 분석할 것이다. 지금은 초보자들이 이해가 안 가시면 일본에 오래오셔서 글을 직접 쓰셔도 좋습니다~.

  • 이것은 함수 실행 중에 런타임 환경에 대한 액세스를 제공하는 키워드입니다.
  • 이것은 객체, 즉 함수가 실행될 때 생성되는 내부 객체이며, this의 포인팅은 함수의 선언 환경이 아니라 함수의 실행 환경에만 관련됩니다.
  • 이것은 포인터 변수이고 JavaScript에는 포인터 개념이 없지만 실제로는 현재 호출 객체를 가리킵니다.
  • 이것은 현재 함수의 실행 환경을 동적으로 가리키는 동적입니다. 다른 환경에서 동일한 함수를 호출할 때 이것의 포인팅도 변경될 수 있습니다.

1. 이것의 구속력 있는 규칙

1. 기본 바인딩

--독립 함수 호출

- 이것이 유효한 어휘 범위는 어디이며, 이것은 어디입니까?

- 엄격 모드에서 브라우저 환경의 전역 개체는 Global Window이고 Node.js 환경에서는 전역 범위를 기본적으로 바인딩할 수 없으므로 다음에만 바인딩할 수 있습니다 undefined.

  // 默认绑定

   function A(){
     console.log(this.a);
   }
   var a=2;
   A();//浏览器:2;node:undefined
复制代码
2. 암시적 바인딩

- 函数引用(비호출!) 컨텍스트 객체가 있을 때 암시적 바인딩 규칙은 이 컨텍스트 객체에 대한 함수 호출에서 이것을 바인딩합니다.

function foo(){
    console.log(this.a);
  }

  var obj={
    a:2,
    foo:foo//函数引用
  }

  console.log(obj.foo());//2 obj就是这个上下文对象
复制代码
3. 암묵적 손실

- 암시적으로 바인딩된 함수가 바인딩된 개체를 잃을 때 기본 바인딩이 참조됩니다.

- 객체 속성 참조 체인 只有上一层或者说最后一层은 호출 위치에서 작동합니다.

 function foo(){
    console.log(this.a);
  }

  var obj={
    a:2,
    foo:foo //隐式绑定的函数
  }

  var obj1={
    a:4,
    obj:obj
  }

  // console.log(obj.foo());//2 显示绑定
  obj1.obj.foo();//2  绑定对象是obj,而不是obj1
复制代码
4. 명시적 바인딩

--call(thisArg, [argsArray])

--apply(thisArg,arguments)

-- bind(thisArg,arguments)함수의 이 지점을 강제로 변경할 수 있습니다.

  obj1.obj.foo();//2

  function Fn(){
    console.log(this.a);
  }

  var o1={
   a:2
  }

  Fn.call(o1);//2 call()
  Fn.apply(o1);//2 apply()
  var bar=Fn.bind(o1)//2 bind()
  bar();
复制代码

둘째, 이 방향

1, 함수의 일반 호출

- 함수 直接调用가 호출된 객체를 가리킬 때 일반적으로 기본 바인딩을 사용합니다.

function A(){
    let a="function name"
    console.log(this.a);
}

var a="window name";
A();//调用A(),当前运行环境是window,this指向window对象
//浏览器:window name;node端:undefined
复制代码
2. 생성자

- 생성자의 this는 항상 다음을 가리킨다.实例化对象

-严格模式下,如果构造函数不加new调用, this 指向的是undefined 如果给他赋值,则会报错.

var Func=function(){
    this.a="我是构造函数的属性";
    this.fun=function(){
        console.log(this);
    }
}
let myFunc=new Func();
myFunc.fun();//Func { a: '我是构造函数的属性', fun: [Function (anonymous)] }
复制代码

-通过构造函数的内部原理,可以将以上代码通过以下三个步骤理解并更写为:

1、在函数体内部最前面隐式的创建一个this={}

2、执行函数中的代码(往this身上挂载属性)

3、隐式的返回这个this(构造函数中只有显式的return 引用类型,才会干扰隐式return值)

var Func=function(){
    // this.a="我是构造函数的属性";
    // this.fun=function(){
    //     console.log(this);
    // }
    let this={
        a:"我是构造函数的属性",
        fun:function(){
            console.log(this);
        }
    }
    return this;
}
let myFunc=new Func();
myFunc.fun();//Func { a: '我是构造函数的属性', fun: [Function (anonymous)] }
复制代码
3、箭头函数

-箭头函数不会创建自己的this,所以它没有自己的this,它只会从自己的作用域链的上一层继承this

-如果外部函数是普通函数,this的指向取决于外部函数的绑定类型,外部函数!=定义箭头函数的外部对象

function foo(){
    var a="function"
    setInterval(()=>{
        console.log(this.a);
    },1000)
}
var a="window"
foo();//箭头函数外部函数是foo;foo没有任何绑定,则使用默认绑定
//浏览器每个1秒打印window;node.js每隔一秒打印undefined
复制代码

三、改变this的指向

1、使用 ES6 的箭头函数

-箭头函数的 this 始终指向函数定义时的 this,而非执行时.

-箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this;否则,this 为 undefined.

var name = "window";
var obj = {
    name : "object",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        setTimeout( () => {
            this.func1()
        },1000);
        // setTimeout(function(){
        //     this.func1()
        // },1000);//定时器里面的回调函数如果不是箭头函数,将会报错
    }
};
obj.func2() //object
复制代码
2、在函数内部使用 _this = this

-var _this = this可防止定时器 被 window 调用,而导致的在 定时器 中的 this 为 window

-定时器会干扰this指向

var name = "window";
var obj = {
    name : "object",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        var _this = this;//这里的 this 是调用 func2 的对象 obj
        setTimeout( () => {
            _this.func1()
        },1000);
    }
};
obj.func2() //object
复制代码
3、使用 apply()、call()、bind()

注意:这三种方法使用的区别,apply()和call()区别在于,两个参数时,后者参数用数组封装;bind()与前两者的区别在于,bind()必须有返回值

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。需要手动调用

var person = {
    fullName: function() {
        return this.name;
    }
}
var person1 = {
    name:"ducky"
}
var person2 = {
    name:"lucky"
}
console.log(person.fullName.call(person1));// ducky
console.log(person.fullName.apply(person2));// ducky
//注意bind()的绑定方式,与call()和apply()不同
var person3=person.bind(person1);
person3();//ducky

复制代码
4、new 实例化一个对象

构造函数的this永远指向通过new运算符创建的实例化对象

var Student=function(sex){
    this.sex=sex;
}
var student=new Student("girl");
console.log(student.sex);//girl
复制代码

추천

출처juejin.im/post/7119455352378097701