>  기사  >  웹 프론트엔드  >  JavaScript에서 이에 대한 종합적인 분석

JavaScript에서 이에 대한 종합적인 분석

韦小宝
韦小宝원래의
2017-11-30 10:41:301241검색

JavaScript물론 객체는 필수입니다. 바로 this 키워드입니다! this 키워드를 사용하면 JavaScript의 코드가 줄어듭니다. 오늘은 JavaScript에서 이를 분석하겠습니다!

암시적 바인딩

이에 대해 일반적으로 말하면 메소드를 호출하는 사람은 누구나 이 메소드가 가리키는 대상을 가리킵니다. 예:

function foo(){
    console.log(this.a)
}
var a = 3;
var obj = {
    a: 2,
    foo: foo
};
obj.foo(); // 输出2,因为是obj调用的foo,所以foo的this指向了obj,而obj.a = 2

여러 호출이 있는 경우 객체 property참조 체인만 이전 또는 마지막 레이어는 다음과 같이 호출 위치에서 역할을 합니다.

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

Implicit loss


가장 일반적인 바인딩 문제 중 하나는 암시적으로 바인딩된 기능이 손실된다는 것입니다. 이는 기본 바인딩을 적용해야 함을 의미하며, 이를 통해 엄격 모드에 있는지 여부에 따라 전역 개체 또는 정의되지 않은 개체에 바인딩됩니다.

function foo() {
    console.log( this.a )
}
var obj1 = {
    a: 2,
    foo: foo
}
var bar = obj1.foo; // 函数别名!
var a = "oops, global"; // a是全局对象的属性
bar(); // "oops, global"

bar는 obj.foo에 대한 참조이지만 실제로는 foo 함수 자체를 참조하므로 이때 bar()는 실제로 아무런 수정 없이 함수 호출이므로 기본 바인딩이 적용됩니다

더 보기 콜백 함수를 전달할 때 미묘하고 일반적이며 예상치 못한 상황이 발생합니다.

function foo() {
    console.log( this.a )
}
function doFoo( fn ){
    // fn 其实引用的是 foo
    fn(); // <-- 调用位置!
}
var obj = {
    a: 2,
    foo: foo
}
var a = "oops, global"; // a是全局对象的属性
doFoo( obj.foo ); // "oops, global"

매개변수 전달은 실제로 일종의 암시적 할당이므로 함수를 전달할 때도 암시적으로 할당되므로 결과는 동일합니다. 앞의 예와 같이 직접 선언한 함수(예: setTimeout 등) 대신 언어 내장 함수에 함수를 전달하면 결과도 동일합니다

Explicit 바인딩

간단히 put 은 호출, 적용, 바인드, 새 바인딩 등을 지정하는 것입니다.

하드 바인딩

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

다음은 간단한 설명입니다. bar 함수에서 foo는 적용 함수를 사용하여 obj를 바인딩합니다. 즉, foo에서 이것은 obj를 가리킬 것입니다. 동시에 인수(전달된 매개변수 수에는 제한이 없음)가 매개변수로 사용되고 bar(3)을 실행할 때 obj가 전달됩니다. a는 첫 번째 출력이고 2와 3이 전달된 다음 foo는 두 값의 합을 반환하므로 b의 값은 5


마찬가지로 이 예에서도 바인딩을 사용할 수 있습니다.

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 바인딩

in the traditional 클래스 지향 언어에서는 new를 사용하여 클래스를 초기화할 때 클래스의 constructor가 호출되지만 JS의 new 메커니즘은 실제로 클래스의 메커니즘과 완전히 다릅니다. 지향적이고 언어 지향적입니다.

new를 사용하여 함수를 호출하거나 생성자 호출이 발생하면 다음 작업이 자동으로 수행됩니다.

새로운 개체 생성(또는 구성)

이 새 개체가 실행됩니다. [[프로토타입]] 연결

이 새 객체는 함수 호출의 this에 바인딩됩니다.

함수가 다른 객체를 반환하지 않으면 newexpression의 함수는 다음과 같이 자동으로 이 새 객체를 반환합니다.

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

new를 사용하여 호출할 때 foo(...) , 우리는 새로운 객체를 생성하고 foo(...) 호출에서 이 객체에 바인딩할 것입니다. new는 함수가 호출될 때 바인딩 동작에 영향을 줄 수 있는 마지막 메서드입니다.

이것은 우선순위

기본 바인딩의 우선순위가 네 가지 규칙 중 가장 낮다는 것은 의심의 여지가 없으므로 먼저 무시해도 됩니다.


암시적 바인딩과 명시적 바인딩 중 어느 것이 더 높은 우선순위를 가집니까? 테스트해 봅시다:

function foo(a){
    console.log(this.a)
}
var obj1 = {
    a: 2,
    foo: foo
}
var obj2 = {
    a: 3,
    foo: foo
}
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call(obj2); // 3
obj2.foo.call(obj1); // 2

명시적 바인딩의 우선순위가 더 높다는 것을 알 수 있습니다. 즉, 판단을 내릴 때 명시적 바인딩이 존재할 수 있는지 여부를 먼저 고려해야 함을 의미합니다.

이제 새 바인딩과 암시적 바인딩 중 누가 더 높은 우선순위를 갖고 누가 더 낮은 우선순위를 갖는지 파악해야 합니다.

function foo(something){
    this.a = something
}
var obj1 = {
    foo: foo
}
var obj2 = {}
obj1.foo(2); 
console.log(obj1.a); // 2
obj1.foo.call(obj2,3);
console.log(obj2.a); // 3
var bar = new obj1.foo(4)
console.log(obj1.a); // 2
console.log(bar.a); // 4

새 바인딩이 암시적 바인딩보다 우선순위가 더 높다는 것을 알 수 있습니다. 하지만 새로운 바인딩과 명시적 바인딩 중 어느 것이 더 높은 우선순위를 갖나요?

function foo(something){
    this.a = something
}
var obj1 = {}
var bar = foo.bind(obj1);
bar(2);
console.log(obj1.a); // 2
var baz = new bar(3);
console.log(obj1.a); // 2
console.log(baz.a); // 3

하드 바인딩에서는 새 바인딩이 이를 수정하므로 새 바인딩이 명시적 바인딩보다 우선순위가 높다는 것을 알 수 있습니다.


new에서 하드 바인딩된 함수를 사용하는 주요 목적은 함수의 일부 매개변수를 미리 설정하여 new로 초기화할 때 나머지 매개변수만 전달할 수 있도록 하는 것입니다. 바인딩(...)의 기능 중 하나는 첫 번째 매개변수(첫 번째 매개변수는 이를 바인딩하는 데 사용됨)를 제외한 모든 매개변수를 기본 함수(이 기술을 "부분 적용"이라고 하며 다음과 같은 유형)에 전달할 수 있다는 것입니다. "커링"). 예를 들면 다음과 같습니다.

function foo(p1,p2){
    this.val = p1 + p2;
}
// 之所以使用null是因为在本例中我们并不关心硬绑定的this是什么
// 反正使用new时this会被修改
var bar = foo.bind(null,&#39;p1&#39;);
var baz = new bar(&#39;p2&#39;);
baz.val; // p1p2
}

커링: 직관적으로 커링은 "일부 매개변수를 수정하면 나머지 매개변수를 허용하는 함수를 얻게 됩니다"라고 말합니다. 따라서 두 개의 변수가 있는 함수 yx의 경우 y = 2가 고정되면 하나의 변수가 있는 함수 2x를 얻습니다

화살표 함수의 이 응용 프로그램

화살표 함수는 이것의 네 가지 표준 규칙을 사용하지 않지만, 외부(함수 또는 전역) 범위를 기준으로 이를 결정합니다.

我们来看一下箭头函数的词法作用域:

function foo() {
    // 返回一个箭头函数
    return (a) => {
        // this继承自foo()
        console.log(this.a)
    };
}
var obj1 = {
    a: 2
};
var obj2 = {
    a: 3
};
var bar = foo.call(obj1);
bar.call(obj2); // 2, 不是3!

foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改。(new也不行!)

总结

如果要判断一个运行中的函数的this绑定,就需要找到这个函数的直接调用位置。找到之后就可以顺序应用下面这四条规则来判断this的绑定对象。

由new调用?绑定到新创建的对象。

由call或者apply(或者bind)调用?绑定到指定的对象。

由上下文对象调用?绑定到那个上下文对象。

默认:在严格模式下绑定到undefined,否则绑定到全局对象。

相关推荐:

JavaScript学习笔记之基础语法

JavaScript 是真正的 OOP 语言吗?

如何用JavaScript修改伪类样式

위 내용은 JavaScript에서 이에 대한 종합적인 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.