>웹 프론트엔드 >JS 튜토리얼 >js에서 This의 우아한 사용

js에서 This의 우아한 사용

php中世界最好的语言
php中世界最好的语言원래의
2018-06-04 10:05:101464검색

이번에는 js에서 This를 우아하게 사용하는 방법을 알려드리겠습니다. js에서 This를 우아하게 사용하기 위한 주의사항은 무엇인가요? 다음은 실제 사례입니다.

함수가 호출되면 활동 기록(실행 컨텍스트)이 생성됩니다.

이 기록에는 함수가 호출된 위치(호출 스택), 함수 호출 방법, 전달된 매개변수 등의 정보가 포함됩니다.

기록되는 속성 중 하나이며 함수 실행 중에 사용됩니다.

이것은 함수 자체나 함수의 범위를 나타내지 않습니다.

이것은 실제로 함수가 호출될 때 발생하는 바인딩이며, 그것이 가리키는 것은 전적으로 함수가 호출되는 위치에 따라 다릅니다.
엄격 모드에서 일반 함수가 호출되면 이는 정의되지 않음을 가리킵니다.

1. 이것을 사용하는 이유

이것은 객체에 대한 참조를 암시적으로 "전달"하는 보다 우아한 방법을 제공하므로 API를 보다 간결하고 재사용하기 쉽게 설계할 수 있습니다.
예:

var me = {  
    name: "fenfei"  };  
  
//不使用this,调用  function speak(name){  
    console.log("Hello, I'm "+ name);  
}  
speak(me.name);     //Hello, I'm fenfei  
  //使用this,调用  function speak(){  
    console.log("Hello, I'm "+ this.name);  
}  
speak.call(me);     //Hello, I'm fenfei


2. 이에 대한 두 가지 오해

(1) 이것은 함수 자체를 가리킵니다.
(2) 이것은 함수의 범위를 가리킵니다.

Scope는 JavaScript 코드를 통해 액세스할 수 없으며 JavaScript 엔진 내부에 존재합니다. 이것을 어휘 범위 조회와 혼합할 때마다 이것이 불가능하다는 점을 명심하십시오!

이것은 작성 시점이 아닌 런타임에 바인딩됩니다. 해당 컨텍스트는 함수가 호출될 때 다양한 조건에 따라 달라집니다. 이것의 바인딩은 함수 선언의 위치와 아무 관련이 없으며 함수 호출 위치(즉, 함수가 호출되는 방식)에만 의존합니다!

3. 바인딩 규칙

1) 기본 바인딩

가장 일반적으로 사용되는 함수 호출 유형: 독립 함수 호출. 다른 규칙을 적용할 수 없는 경우 이 규칙을 기본 규칙으로 생각하세요.
예:

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

2) 암시적 규칙

암시적 바인딩의 규칙은 호출 위치에 컨텍스트 객체가 있는지, 아니면 객체가 소유하거나 포함하는지 여부입니다.

rreee

. foo()가 호출되면 this는 obj에 바인딩되므로 this.a와 obj.a는 동일합니다.

하지만 때로는 암시적 손실이 발생하기도 합니다.

rreee

. bar는 obj.foo에 대한 참조이지만 실제로는 foo 함수 자체를 참조합니다.
그래서 bar()는 실제로는 아무런 수정 없이 기본 바인딩이 적용된 함수 호출입니다.
3) 바인딩 표시

전화 및 적용
. JavaScript에서는 호출과 적용이 이의 부모와 같습니다. 이가 사는 곳이면 어디든 살아야 하고 순종해야 합니다! 매개변수가 없으면 현재 개체는 window
예:

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

입니다. 그 중 getName 함수에 있습니다. 이것이 어디에 있든, 기능이 실행될 때 위치를 찾아야 합니다. 이때 getName 함수가 실행 중일 때의 위치는
(1) getName(xpg);//Global
당연히 getName 함수가 위치한 객체는 window이므로 이것의 home은 in에 있어야 합니다. window, 즉 window 객체를 가리키는 경우 getName이 반환한 this.name은 실제로는 window.name이므로 경고는 "전역"으로 표시됩니다!
(2) getName.call(xpg);//부분
. 그 중 call은 this의 홈이 xpg 개체임을 지정합니다. 이는 강제로 xpg에서만 해결되므로 this는 이때 xpg 개체를 가리키며 this.name은 실제로 xpg.name이므로 경고가 나옵니다. "로컬"로!

바인드()
. 바인딩 메소드는 es5부터 제공되므로 ie9+에서만 지원됩니다. 예:

function foo() {  console.log(this.a);
}var obj = {    a: 2,    foo: foo
};var bar = obj.foo; // 函数  var a = "oops, global"; //bar(); // "oops, global"

console.log(o.f(), o.g()) // 37, test //o.f()는 속성을 통해 호출됩니다. 그리고 이것은 객체 o를 가리킵니다. //특별한 점은 새로 바인딩된 메서드를 객체의 속성으로 호출하더라도 //o.g()는 여전히 이전 바인딩을 따르기 때문에 대답은 다음과 같습니다. 테스트는 g


4) 새 바인딩이 아닙니다.

new의 이 바인딩은 수정할 수 없습니다!

새 호출 함수는 다음 작업을 자동으로 수행합니다.

(1) 새로운 개체를 생성(또는 구성)합니다.
(2) 이 새 개체는 [[Prototype]]을 수행하여 연결됩니다. 새 객체는 함수 호출의 여기에 바인딩됩니다.
(4) 함수가 다른 객체를 반환하지 않으면 새 표현식의 함수 호출이 자동으로 이 새 객체를 반환합니다.
예:

var name="全局";var xpg={    name:"局部"};function getName(){
    alert(this.name);
}
getName(xpg);//全局getName.call(xpg);//局部getName.call();//全局

위의 예에서는 일반적으로 또는

생성자

형식으로 호출할 수 있는 Person 함수가 먼저 정의됩니다. . 정상적으로 호출되면 일반 함수처럼 실행되어 문자열이 출력됩니다. . new 연산자를 통해 전달되면 새 개체가 생성됩니다.
. 일반적인 호출을 할 때에는 앞서 언급한 것처럼 기본 바인딩 규칙이 적용되어 전역 객체에 바인딩됩니다. 이때 전역 객체에는 name과 age라는 두 가지 속성이 추가됩니다.
. new 연산자를 통해 호출되면 함수는 객체를 반환합니다. 출력 결과에서 this 객체가 반환된 객체에 바인딩되어 있음을 알 수 있습니다.

따라서 소위 새 바인딩이란 함수가 new 연산자를 통해 호출되면 새 개체가 생성되고 생성자에서 이 개체에 바인딩된다는 의미입니다.

4. 우선순위

새 바인딩 > 호출 적용 등 디스플레이 바인딩 > 암시적 바인딩 > 기본 바인딩.

了解了函数调用中this绑定的四条规则,需要做的就是找到函数的调用位置并判断对应哪条规则。

(1)函数是否是new绑定?如果是,this绑定的是新创建的对象。
var bar = new Foo();
(2)函数是否通过call、apply显示绑定或硬绑定?如果是,this绑定的是指定的对象。
var bar = foo.call(obj);
(3)函数是否在某个上下文对象中隐式调用?如果是,this绑定的是那个上下文对象。
var bar = obj.foo();
(4)上述全不是,则使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局window对象。
var bar = foo();

new绑定和call、apply无法一起使用,因此不能使用new foo.call(obj).

五、this绑定例外

1)被忽略的绑定

如果你把null或者undefined作为this的绑定对象传入call、apply或者bind。
这些值在调用时会被忽略,实际应用的是默认绑定规则。
eg:

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

2)间接引用
eg:

function foo() {  console.log(this.a);
}var a = 2; 
var o = { a: 3, foo: foo }; 
var p = { a: 4 }; 
o.foo(); // 3(p.foo = o.foo)(); // 2

赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo()。
3)当前对象不明确时的this

当没有明确的执行时的当前对象时,this指向全局对象window。
例如对于全局变量引用的函数上我们有:

var name = "Tom";var Bob = {    name: "Bob",    show: function(){
        alert(this.name);
    }
}var show = Bob.show;
show();  //Tom

。你可能也能理解成show是window对象下的方法,所以执行时的当前对象时window。但局部变量引用的函数上,却无法这么解释:

var name = "window";var Bob = {    name: "Bob",    showName: function(){
        alert(this.name);
    }
};var Tom = {    name: "Tom",    showName: function(){        var fun = Bob.showName;
        fun();
    }
};
Tom.showName();  //window

4)在浏览器中setTimeout、setInterval和匿名函数执行时的当前对象是全局对象window:

var name = "Bob";  
var nameObj ={  
      name : "Tom",  
      showName : function(){  
          alert(this.name);  
      },  
      waitShowName : function(){  
          setTimeout(this.showName, 1000);  
      }  
 };  
 nameObj.waitShowName();

5)软绑定
eg:

var count=2;var obj={    count:0,    cool:function coolFn(){        console.log(this.count);//0
         var self=this;        if(self.count<1){
            setTimeout(function timer(){
                self.count++;                console.log("awesome?");                console.log(self.count);//1
                console.log(this.count);//2
            },100);
        }
    }
};
obj.cool();

6)dom事件中的this

(1)直接在dom元素中使用
1eb9ebab541c78a07af4b7a6c86d652c

分析:对于dom元素的一个onclick(或其他如onblur等)属性,它为所属的html元素所拥有,直接在它触发的函数里写this,this应该指向该html元素。

(2)给dom元素注册js函数

a、不正确的方式

<script type="text/javascript">
  function thisTest(){
  alert(this.value); // 弹出undefined, this在这里指向??}</script><input id="btnTest" type="button" value="提交" onclick="thisTest()" />

。分析:onclick事件直接调用thisTest函数,程序就会弹出undefined。
因为thisTest函数是在window对象中定义的, 所以thisTest的拥有者(作用域)是window,thisTest的this也是window。而window是没有value属性的,所以就报错了。

b、正确的方式

<input id="btnTest" type="button" value="提交" /><script type="text/javascript">
  function thisTest(){
  alert(this.value); 
}document.getElementById("btnTest").onclick=thisTest; 
//给button的onclick事件注册一个函数</script>

。分析:在前面的示例中,thisTest函数定义在全局作用域(这里就是window对象),所以this指代的是当前的window对象。
而通过document.getElementById(“btnTest”).onclick=thisTest;这样的形式,其实是将btnTest的onclick属性设置为thisTest函数的一个副本,在btnTest的onclick属性的函数作用域内,this归btnTest所有,this也就指向了btnTest。

因为多个不同的HTML元素虽然创建了不同的函数副本,但每个副本的拥有者都是相对应的HTML元素,各自的this也都指向它们的拥有者,不会造成混乱。
eg:

<input id="btnTest1" type="button" value="提交1" onclick="thisTest()" /><input id="btnTest2" type="button" value="提交2" /><script type="text/javascript">function thisTest(){this.value="提交中";
}var btn=document.getElementById("btnTest1");
alert(btn.onclick); //第一个按钮函数var btnOther=document.getElementById("btnTest2");
btnOther.onclick=thisTest;
alert(btnOther.onclick); //第二个按钮函数</script>

其弹出的结果是:

//第一个按钮function onclick(){
  thisTest()
}//第二个按钮function thisTest(){  this.value="提交中";
}

7)this词法(ES6:箭头函数)

箭头函数不使用function关键字定义,而是使用“胖箭头”的操作符=>定义;箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。
eg:

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的也不能!)

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样利用JS做出引用传递与值传递

使用JS实做出加密解密操作

위 내용은 js에서 This의 우아한 사용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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