이것이 어디에 있는지에 따라 이것을 이해하기 위해 상황은 대략 세 가지 유형으로 나눌 수 있습니다.
1. 함수에서 : 이것은 일반적으로 암시 적 매개 변수입니다.
2. 함수 외부 (최상위 범위) : 브라우저에서 이것은 글로벌 객체를 나타냅니다. Node.js에서는 모듈의 내보내기를 나타냅니다.
3. 평가 ()로 전달 된 문자열 : eval ()가 직접 호출되면 현재 객체를 나타냅니다. 평가 ()를 간접적으로 호출하면 글로벌 객체를 나타냅니다.
이러한 범주에 대한 해당 테스트를 수행했습니다.
1. 이것은 함수에서
함수는 기본적으로 JS에서 호출 된 모든 구조를 나타낼 수 있으므로 이것이 사용되는 가장 일반적인 시나리오이기도하며 기능은 다음 세 가지 역할로 세분화 될 수 있습니다.
실제 기능
건설자
방법
1.1 이것은 실제 기능으로
실제 기능에서, 이것의 값은 그것이 위치한 컨텍스트에 의존하는 패턴입니다.
경사 모드 : 이것은 글로벌 객체 (브라우저의 창)을 나타냅니다.
코드 사본은 다음과 같습니다.
함수 sloppyfunc () {
console.log (this === 창); // 진실
}
sloppyfunc ();
엄격한 모드 : 이것의 값은 정의되지 않았습니다.
코드 사본은 다음과 같습니다.
함수 strictfunc () {
'엄격한 사용';
Console.log (this === 정의되지 않은); // 진실
}
strictfunc ();
이것은 함수의 암시 적 매개 변수이므로 그 값은 항상 동일합니다. 그러나 Call () 또는 apply () 메소드를 사용하여 값을 표시 하여이 값을 정의 할 수 있습니다.
코드 사본은 다음과 같습니다.
함수 func (arg1, arg2) {
Console.log (this); // 1
Console.log (arg1); // 2
Console.log (arg2); // 3
}
func.call (1, 2, 3); // (this, arg1, arg2)
func.Apply (1, [2, 3]); // (this, arraywithargs)
1.2 이것은 생성자에 있습니다
새로운 기능을 새로운 것을 통해 생성자로 사용할 수 있습니다. 새 작업은 새 객체를 생성 하고이 객체를이를 통해 생성자로 전달합니다.
코드 사본은 다음과 같습니다.
var는 이것을 저장했습니다.
함수 sonst () {
savedthis = this;
}
var inst = new ranst ();
console.log (savedthis === inst); // 진실
JS에서 새로운 운영의 구현 원리는 다음 코드에 대략 표시됩니다 (보다 정확한 구현은 여기를 참조하십시오.이 구현도 더 복잡합니다).
코드 사본은 다음과 같습니다.
기능 NewOperator (Constr, ArraywitHargs) {
var thisvalue = object.create (cost.prototype);
constr.Apply (thisvalue, arraywithargs);
이 값을 반환하십시오.
}
1.3이 방법에서
방법에서, 이것의 사용은 전통적인 객체 지향 언어로 더 많은 경향이 있습니다. 수신기는 이것에 의해 지적, 즉이 방법을 포함하는 대상을 가리 킵니다.
코드 사본은 다음과 같습니다.
var obj = {
방법 : function () {
console.log (this === obj); // 진실
}
}
obj.method ();
2. 이것은 범위에 있습니다
브라우저에서 스코프는 글로벌 범위이며,이 글로벌 객체 (예 : 창)을 나타냅니다.
코드 사본은 다음과 같습니다.
<cript>
console.log (this === 창); // 진실
</스크립트>
Node.js에서는 일반적으로 모듈에서 함수를 실행합니다. 따라서 최상위 범위는 매우 특별한 모듈 범위입니다.
코드 사본은 다음과 같습니다.
//`global` (`window '아님) 글로벌 개체를 참조하십시오.
console.log (math === global.math); // 진실
//`이것은 글로벌 객체를 언급하지 않습니다.
console.log (this! == global); // 진실
//`이것은 모듈의 내보내기를 나타냅니다.
console.log (this === module.exports); // 진실
3. 이것은 평가 ()에서
평가 ()는 직접 (함수 이름을 '평가'라고 부르면) 또는 간접적으로 (Call ()과 같은 다른 방법으로)을 직접 호출 할 수 있습니다. 자세한 내용은 여기를 참조하십시오.
코드 사본은 다음과 같습니다.
// 실제 함수
함수 sloppyfunc () {
Console.log (Eval ( 'this') === 창); // 진실
}
sloppyfunc ();
함수 strictfunc () {
'엄격한 사용';
Console.log (Eval ( 'this') === 정의되지 않은); // 진실
}
strictfunc ();
// 생성자
var는 이것을 저장했습니다.
함수 sonst () {
SavedThis = Eval ( 'this');
}
var inst = new ranst ();
console.log (savedthis === inst); // 진실
// 메소드
var obj = {
방법 : function () {
Console.log (Eval ( 'this') === OBJ); // 진실
}
}
obj.method ();
4. 이와 관련된 함정
아래에 소개 될 이와 관련된 3 개의 트랩에주의해야합니다. 다음 예에서 엄격한 모드를 사용하면 코드의 보안이 향상 될 수 있습니다. 실제 기능에서는 이것의 가치가 정의되지 않으므로 무언가 잘못되면 경고를 받게됩니다.
4.1 새로운 사용을 잊었습니다
생성자를 호출하는 데 새로운 것을 사용하지 않는 경우 실제로 실제 기능을 사용하고 있습니다. 그래서 이것은 당신이 기대하는 가치가 아닙니다. 조잡한 모드에서는 창을 가리키며 글로벌 변수를 생성합니다.
코드 사본은 다음과 같습니다.
기능 지점 (x, y) {
this.x = x;
this.y = y;
}
var p = 점 (7, 5); // 우리는 새로 잊어 버립니다!
console.log (p === 정의되지 않은); // 진실
// 글로벌 변수가 생성되었습니다.
Console.log (x); // 7
Console.log (y); // 5
그러나 엄격한 모드를 사용하는 경우 경고가 계속 표시됩니다 (이 === 정의되지 않은).
코드 사본은 다음과 같습니다.
기능 지점 (x, y) {
'엄격한 사용';
this.x = x;
this.y = y;
}
var p = 점 (7, 5);
// typeerror : 정의되지 않은 속성 'x'를 설정할 수 없습니다
4.2 부적절한 사용 방법
메소드의 값을 직접 가져 오면 (호출되지 않음)이 메소드를 함수로 사용합니다. 매개 변수로 메소드를 함수 또는 호출 방법으로 전달하려면이 작업을 수행 할 가능성이 높습니다. Settimeout () 및 등록 이벤트 처리기의 경우입니다. Callit () 메소드를 사용 하여이 시나리오를 시뮬레이션합니다.
코드 사본은 다음과 같습니다.
/** settimeout () 및 setimmediate ()와 유사합니다.*/
함수 콜리트 (func) {
func ();
}
조잡한 모드에서 메소드를 함수로 호출하는 경우 * 이것은 전역 객체를 가리키므로 그 후에 생성 된 것은 글로벌 변수가됩니다.
코드 사본은 다음과 같습니다.
var 카운터 = {
수 : 0,
// 조잡한 모드 메소드
Inc : function () {
this.count ++;
}
}
Callit (Counter.inc);
// 작동하지 않았습니다.
Console.log (Counter.Count); // 0
// 대신 글로벌 변수가 생성되었습니다
// (NAN은 ++를 정의되지 않은 것에 적용한 결과) :
Console.log (count); // 난
엄격한 모드 에서이 작업을 수행하면 정의되지 않은 결과로 원하는 결과를 얻지 못하지만 적어도 경고를받을 수 있습니다.
코드 사본은 다음과 같습니다.
var 카운터 = {
수 : 0,
// 엄격한 모드 메소드
Inc : function () {
'엄격한 사용';
this.count ++;
}
}
Callit (Counter.inc);
// typeerror : 정의되지 않은 속성 'count'를 읽을 수 없습니다
Console.log (Counter.Count);
예상 결과를 얻으려면 bind ()를 사용할 수 있습니다.
코드 사본은 다음과 같습니다.
var 카운터 = {
수 : 0,
Inc : function () {
this.count ++;
}
}
callit (counter.inc.bind (counter));
// 작동했습니다!
Console.log (Counter.Count); // 1
bind ()는이 값을 항상 반대하도록 설정할 수있는 다른 함수를 만듭니다.
4.3 이걸 숨기십시오
메소드에서 함수를 사용하면 종종 기능이 자체적으로 있다는 것을 무시합니다. 이것은 방법과 다르 므로이 두 가지를 함께 혼합 할 수 없습니다. 자세한 내용은 다음 코드를 참조하십시오.
코드 사본은 다음과 같습니다.
var obj = {
이름 : '제인',
친구 : [ 'Tarzan', 'Cheeta'],
루프 : function () {
'엄격한 사용';
this.friends.foreach (
기능 (친구) {
console.log (this.name+'know'+friend);
}
);
}
};
obj.loop ();
// TypeError : 정의되지 않은 속성 '이름'을 읽을 수 없습니다
이 기능의 값이 정의되지 않으므로 위의 예제의 함수의 이름은 사용할 수 없으며 메소드 루프 () 에서이와 다릅니다. 다음은이 문제를 해결하기위한 세 가지 아이디어입니다.
1. this = this, 이것을 변수에 할당하여 명시 적으로 나타나도록 (자체는 이것을 저장하는 데 사용되는 매우 일반적인 변수 이름임을 제외하고), 해당 변수를 사용합니다.
코드 사본은 다음과 같습니다.
루프 : function () {
'엄격한 사용';
var that = this;
this.friends.foreach (function (friend) {
console.log (that.name+'knowledge'+friend);
});
}
2. bind (). bind ()를 사용하여 함수를 만듭니다. 이 함수는 항상 전달하려는 값을 포함합니다 (다음 예에서는이 방법에서).
코드 사본은 다음과 같습니다.
루프 : function () {
'엄격한 사용';
this.friends.foreach (function (friend) {
console.log (this.name+'know'+friend);
} .bind (this));
}
3. Foreach의 두 번째 매개 변수를 사용하십시오. Foreach의 두 번째 매개 변수는 콜백 함수로 전달되어 콜백 함수의 상태로 사용됩니다.
코드 사본은 다음과 같습니다.
루프 : function () {
'엄격한 사용';
this.friends.foreach (function (friend) {
console.log (this.name+'know'+friend);
}, 이것);
}
5. 모범 사례
이론적으로, 나는 실제 기능이 그 자체에 속하지 않는다고 생각하며, 위의 솔루션은이 아이디어를 기반으로합니다. ECMAScript 6은 화살표 기능을 사용 하여이 효과를 달성하는데, 이는 자체가없는 함수입니다. 그러한 함수에서는 암시 적 존재가 있는지 걱정하지 않고 마음대로 사용할 수 있습니다.
코드 사본은 다음과 같습니다.
루프 : function () {
'엄격한 사용';
// foreach ()의 매개 변수는 화살표 함수입니다
this.friends.foreach (friend => {
//`this '는 루프의`this'입니다
console.log (this.name+'know'+friend);
});
}
나는 이것을 실제 함수의 추가 매개 변수로 간주하는 API를 좋아하지 않습니다.
코드 사본은 다음과 같습니다.
이전에 (function () {
this.addmatchers ({
TobeInrange : 함수 (시작, 끝) {
...
}
});
});
명시 적으로 전달 된 암시 적 매개 변수를 작성하면 코드는 이해하는 것이 더 잘 보이며 이는 화살표 기능의 요구 사항과 일치합니다.
코드 사본은 다음과 같습니다.
이전에 (API => {
api.addmatchers ({
TobeInrange (시작, 끝) {
...
}
});
});