换个思路清楚Javascript中的this,的三种接纳情形

时间:2019-09-24 18:24来源:关于计算机
换个思路清楚Javascript中的this 2017/07/27 · JavaScript· this 原稿出处: Leechikit    在互连网海人民广播电视台湾大学文章都对 Javascript 中的 this 做了详细的介绍,但基本上是介绍各种绑定情

换个思路清楚Javascript中的this

2017/07/27 · JavaScript · this

原稿出处: Leechikit   

在互连网海人民广播电视台湾大学文章都对 Javascript 中的 this 做了详细的介绍,但基本上是介绍各种绑定情势或调用情势下 this 的针对性,于是小编想有一个集结的笔触来越来越好驾驭 this 指向,使我们更好判断,以下有局地内容不是原理,而是一种解题思路。

Javascript 中的 this,偶然候令人迷惑,所以总括了刹那间有关this指向的主题素材。

从call方法开头

call 方法允许切换函数试行的上下文景况(context),即 this 绑定的目的。

超越50%介绍 this 的稿子中都会把 call 方法放到最终介绍,但此文大家要把 call 方法放在第一人介绍,并从 call 方法切入来商讨 this ,因为 call 函数是显式绑定 this 的针对,大家来拜会它怎么着模拟实现(不考虑传入 nullundefined 和原始值):

Function.prototype.call = function(thisArg) { var context = thisArg; var arr = []; var result; context.fn = this; for (let i = 1, len = arguments.length; i < len; i++) { arr.push('arguments[' + i + ']'); } result = eval("context.fn(" + arr + ")"); delete context.fn; return result; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function.prototype.call = function(thisArg) {
    var context = thisArg;
    var arr = [];
    var result;
 
    context.fn = this;
 
    for (let i = 1, len = arguments.length; i < len; i++) {
        arr.push('arguments[' + i + ']');
    }
 
    result = eval("context.fn(" + arr + ")");
 
    delete context.fn;
 
    return result;
}

从上述代码大家得以看看,把调用 call 方法的函数作为第一个参数对象的章程,此时也正是把第贰个参数对象作为函数实行的上下文情状,而 this 是指向函数试行的上下文蒙受的,由此 this 就本着了第4个参数对象,落成了 call 方法切换函数实践上下文碰着的法力。

在函数中 this 到底取何值,是在函数真正被调用施行的时候鲜明下来的,函数定义的时候分明不了。

指标方法中的this

在模拟 call 方法的时候,大家运用了对象方法来改造 this 的指向。调用对象中的方法时,会把对象作为艺术的上下文情况来调用。

既然 this 是指向实行函数的上下文景况的,那我们先来商讨一下调用函数时的实行上下文情状。

下边小编门来寻访调用对象方法时进行上下文是如何的:

var foo = { x : 1, getX: function(){ console.log(this.x); } } foo.getX();

1
2
3
4
5
6
7
var foo = {
    x : 1,
    getX: function(){
        console.log(this.x);
    }
}
foo.getX();

永利皇宫463手机版 1

从上航海用教室中,大家得以观望getX情势的调用者的上下文是foo,因此getX办法中的 this 指向调用者上下文foo,转换成 call 方法为foo.getX.call(foo)

下边大家把其他函数的调用方式都按调用对象方法的思路来改变。

因为 this 的取值是函数推行上下文(context)的一片段,每回调用函数,都会时有爆发一个新的实践上下文意况。今世码中应用了 this,那一个 this 的值就平昔从试行的左右文中获取了,而不会从效果域链中找找。

构造函数中的this

function Foo(){ this.x = 1; this.getX = function(){ console.log(this.x); } } var foo = new Foo(); foo.getX();

1
2
3
4
5
6
7
8
function Foo(){
    this.x = 1;
    this.getX = function(){
        console.log(this.x);
    }
}
var foo = new Foo();
foo.getX();

执行 new 借使不考虑原型链,只怀想上下文的切换,就一定于先创制一个空的对象,然后把那个空的对象作为构造函数的上下文,再去奉行构造函数,最终回来那几个指标。

var newMethod = function(func){ var context = {}; func.call(context); return context; } function Foo(){ this.x = 1; this.getX = function(){ console.log(this.x); } } var foo = newMethod(Foo); foo.getX();

1
2
3
4
5
6
7
8
9
10
11
12
13
var newMethod = function(func){
    var context = {};
    func.call(context);
    return context;
}
function Foo(){
    this.x = 1;
    this.getX = function(){
        console.log(this.x);
    }
}
var foo = newMethod(Foo);
foo.getX();

至于 this 的取值,概况上得以分为以下多样处境:

永利皇宫463手机版 2

气象一:全局 & 调用普通函数

DOM事件处理函数中的this

DOMElement.addEventListener('click', function(){ console.log(this); });

1
2
3
DOMElement.addEventListener('click', function(){
    console.log(this);
});

把函数绑定到DOM事件时,能够作为在DOM上扩张贰个函数方法,当接触那一个事件时调用DOM上相应的风云措施。

DOMElement.clickHandle = function(){ console.log(this); } DOMElement.clickHandle();

1
2
3
4
DOMElement.clickHandle = function(){
    console.log(this);
}
DOMElement.clickHandle();

永利皇宫463手机版 3

在大局情况中,this 永恒指向 window。

一般来讲函数中的this

var x = 1; function getX(){ console.log(this.x); } getX();

1
2
3
4
5
var x = 1;
function getX(){
    console.log(this.x);
}
getX();

这种情景下,大家创造一个虚构上下文对象,然后普通函数作为这几个编造上下文对象的法子调用,此时普通函数中的this就针对了这一个编造上下文。

那这么些设想上下文是怎么着呢?在非严峻格局下是全局上下文,浏览器里是 window ,NodeJs里是 Global ;在严酷格局下是 undefined

var x = 1; function getX(){ console.log(this.x); } [viturl context].getX = getX; [viturl context].getX();

1
2
3
4
5
6
7
var x = 1;
function getX(){
    console.log(this.x);
}
 
[viturl context].getX = getX;
[viturl context].getX();

永利皇宫463手机版 4

console.log(this === window);    //true

闭包中的this

var x = 1; var foo = { x: 2, y: 3, getXY: function(){ (function(){ console.log("x:" + this.x); console.log("y:" + this.y); })(); } } foo.getXY();

1
2
3
4
5
6
7
8
9
10
11
12
var x = 1;
var foo = {
    x: 2,
    y: 3,
    getXY: function(){
        (function(){
            console.log("x:" + this.x);
            console.log("y:" + this.y);
        })();
    }
}
foo.getXY();

这段代码的上下文如下图:永利皇宫463手机版 5

此处必要静心的是,大家再钻探函数中的 this 指向时,只须要关爱 this 所在的函数是何许调用的, this 所在函数外的函数调用都是浮云,是不要求关爱的。由此在具备的图示中,大家只须求关注深红色框中的内容。

为此这段代码大家关心的一对独有:

(function(){ console.log(this.x); })();

1
2
3
(function(){
    console.log(this.x);
})();

与平时函数调用同样,创立三个虚拟上下文对象,然后普通函数作为这几个虚构上下文对象的主意马上调用,佚名函数中的 this 也就对准了这几个虚构上下文。永利皇宫463手机版 6

一般函数在调用时候(注意不是构造函数,前边不加 new),其中的 this 也是指向 window。

参数中的this

var x = 1; var foo = { x: 2, getX: function(){ console.log(this.x); } } setTimeout(foo.getX, 1000);

1
2
3
4
5
6
7
8
var x = 1;
var foo = {
    x: 2,
    getX: function(){
        console.log(this.x);
    }
}
setTimeout(foo.getX, 1000);

函数参数是值传递的,因而地点代码等同于以下代码:

var getX = function(){ console.log(this.x); }; setTimeout(getX, 1000);

1
2
3
4
var getX = function(){
    console.log(this.x);
};
setTimeout(getX, 1000);

接下来大家又重返了常备函数调用的难点。

var x = 10;

全局中的this

大局中的 this 指向全局的上下文

var x = 1; console.log(this.x);

1
2
var x = 1;
console.log(this.x);

永利皇宫463手机版 7

function foo(){

复杂气象下的this

var x = 1; var a = { x: 2, b: function(){ return function(){ return function foo(){ console.log(this.x); } } } }; (function(){ var x = 3; a.b()()(); })();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var x = 1;
var a = {
    x: 2,
    b: function(){
        return function(){
            return function foo(){
                console.log(this.x);
            }        
        }
    }
};
 
(function(){
    var x = 3;
    a.b()()();
})();

看来上边的景色是有众四个函数,但大家只须求关怀 this 所在函数的调用方式,首先我们来简化一下之类:

var x = 1; (function(){ var x = 3; var foo = function(){ console.log(this.x); } foo(); });

1
2
3
4
5
6
7
8
var x = 1;
(function(){
    var x = 3;
    var foo = function(){
        console.log(this.x);
    }
    foo();
});

this 所在的函数 foo 是个常备函数,大家创立八个虚拟上下文对象,然后普通函数作为这几个设想上下文对象的格局即刻调用。由此这一个 this本着了那一个编造上下文。在非严刻形式下是全局上下文,浏览器里是 window ,NodeJs里是 Global ;在严谨形式下是 undefined

console.log(this);    //Window

总结

在急需看清 this 的对准时,大家能够安装这种思路来通晓:

  • 判断 this 在大局中O兰德酷路泽函数中,若在大局中则 this 指向全局,若在函数中则只关怀那么些函数并再而三判定。
  • 判断 this 所在函数是或不是作为指标方法调用,假使则 this 指向这些指标,不然继续操作。
  • 创制二个虚构上下文,并把this所在函数作为这些编造上下文的措施,此时 this 指向那么些虚构上下文。
  • 在非严酷形式下虚构上下文是大局上下文,浏览器里是 window ,Node.js里是 Global ;在严俊形式下是 永利皇宫463手机版,undefined

图示如下:

永利皇宫463手机版 8

 

1 赞 6 收藏 评论

永利皇宫463手机版 9

console.log(this.x);  //10

}

foo();

情状二:构造函数

所谓的构造函数正是由三个函数 new 出来的目的,一般构造函数的函数名首字母大写,举个例子像 Object,Function,Array 这个都属于构造函数。

function Foo(){

this.x = 10;

console.log(this);    //Foo {x:10}

}

var foo = new Foo();

console.log(foo.x);      //10

上述代码,假使函数作为构造函数使用,那么内部的 this 就代表它将在 new 出来的靶子。

然则只要直白调用 Foo 函数,并非 new Foo(),那就改为情况1,那时候 Foo() 就成为日常函数。

function Foo(){

this.x = 10;

console.log(this);    //Window

}

var foo = Foo();

console.log(foo.x);      //undefined

情形三:对象方法

借使函数作为对象的艺术时,方法中的 this 指向该对象。

var obj = {

x: 10,

foo: function () {

console.log(this);        //Object

console.log(this.x);      //10

}

};

obj.foo();

瞩目:如若在指标方法中定义函数,那么境况就不相同了。

var obj = {

x: 10,

foo: function () {

function f(){

console.log(this);      //Window

console.log(this.x);    //undefined

}

f();

}

}

obj.foo();

能够如此清楚:函数 f 纵然是在 obj.foo 内部定义的,但它照旧属于三个不乏先例函数,this 仍指向 window。

在此处,借使想要调用上层效率域中的变量 obj.x,能够选拔 self 缓存外界this 变量。

var obj = {

x: 10,

foo: function () {

var self = this;

function f(){

console.log(self);      //{x: 10}

console.log(self.x);    //10

}

f();

}

}

obj.foo();

若是 foo 函数不作为对象方法被调用:

var obj = {

x: 10,

foo: function () {

console.log(this);      //Window

console.log(this.x);    //undefined

}

};

var fn = obj.foo;

fn();

obj.foo 被赋值给一个全局变量,并未当做 obj 的二个属性被调用,那么此时 this 的值是 window。

情状四:构造函数 prototype 属性

function Foo(){

this.x = 10;

}

Foo.prototype.getX = function () {

console.log(this);        //Foo {x: 10, getX: function}

console.log(this.x);      //10

}

var foo = new Foo();

foo.getX();

在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不止如此,即就是在全部原型链中,this 代表的也是当下指标的值。

情况五:函数用 call、apply或者 bind 调用。

var obj = {

x: 10

}

function foo(){

console.log(this);    //{x: 10}

console.log(this.x);  //10

}

foo.call(obj);

foo.apply(obj);

foo.bind(obj)();

当八个函数被 call、apply 或许 bind 调用时,this 的值就取传入的指标的值。

情况六:DOM event this

在贰个 HTML DOM 事件管理程序里,this 始终指向这一个管理程序所绑定的 HTML DOM 节点:

function Listener(){

document.getElementById('foo').add伊芙ntListener('click', this.handleClick);    //这里的 this 指向 Listener 这些目的。不是重申的是这里的 this

}

Listener.prototype.handleClick = function (event) {

console.log(this);    //

}

var listener = new Listener();

document.getElementById('foo').click();

本条很好驾驭,就相当于是给函数字传送参,使 handleClick 运维时上下文字改良变了,也便是下边那样的代码:

var obj = {

x: 10,

fn: function() {

console.log(this);        //Window

console.log(this.x);      //undefined

}

};

function foo(fn) {

fn();

}

foo(obj.fn);

你也能够用经过 bind 切换上下文:

function  Listener(){

document.getElementById('foo').addEventListener('click',this.handleClick.bind(this));

}

Listener.prototype.handleClick = function (event) {

console.log(this);    //Listener {}

}

var listener = new Listener();

document.getElementById('foo').click();

前种种情形实际上能够计算为: this 指向调用该办法的靶子。

动静七:箭头函数中的 this

当使用箭头函数的时候,意况就一丈差九尺了:箭头函数内部的 this 是词法成效域,由上下文鲜明。

var obj = {

x: 10,

foo: function() {

var fn = () => {

return () => {

return () => {

console.log(this);      //Object {x: 10}

console.log(this.x);    //10

}

}

}

fn()()();

}

}

obj.foo();

后天,箭头函数完全修复了 this 的针对,this 总是指向词法功用域,约等于外围调用者 obj。

假定利用箭头函数,此前的这种 hack 写法:

var self = this;

就不再须要了。

var obj = {

x: 10,

foo: function() {

var fn = () => {

return () => {

return () => {

console.log(this);    // Object {x: 10}

console.log(this.x);  //10

}

}

}

fn.bind({x: 14})()()();

fn.call({x: 14})()();

}

}

obj.foo();

出于 this 在箭头函数中早就遵照词法功能域绑定了,所以,用 call()大概apply()调用箭头函数时,不可能对 this 实行绑定,即传入的第二个参数被忽视。

编辑:关于计算机 本文来源:换个思路清楚Javascript中的this,的三种接纳情形

关键词: