My Little World

关于this

普通函数中的this

  1. this总是代表它的直接调用者, 例如 obj.func ,那么func中的this就是obj
    2.在默认情况(非严格模式下,未使用 ‘use strict’),没找到直接调用者,则this指的是 window
    3.在严格模式下,没有直接调用者的函数中的this是 undefined
    4.使用call,apply,bind绑定的,this指的是 绑定的对象,
    bind绑定一次后不会改变,且bind 的执行的结果返回的是绑定了一个对象的新函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    1
    function test() {
    console.log(this);//window
    }
    test();

    2
    function test() {
    'use strict';
    console.log(this);//undefined
    }
    test();

    3
    window.val = 1;
    var obj = {
    val: 2,
    fn: function () {
    this.val *= 2; //普通函数,this指向调用者
    val *= 2;
    console.log(this.val);
    console.log(val);
    }
    };
    obj.fn();// 4 2
    var func = obj.fn;
    func(); //8 8
    //obj.fn()执行时,val 没有在fn的作用域里面定义,则去obj.fn()的作用域里面找,obj.fn()位于window,window.val是1;this指向obj,this.val是2
    //func()执行时,window.val由于执行obj.fn(),现在是2;func()在window作用域下执行,this就是window,所以this.val和val都是window.val

    4
    function f() {
    var test = 'in the f!';
    setTimeout(function(){ //是函数就会建立作用域
    console('inner '+ test) // inner in the f!
    }, 0);
    }
    //以上代码等于
    function f() {
    var test = 'in the f!';

    function ff() {
    alert('inner ' + test) //test在ff里面没定义,但在f里面进行了定义
    } // 能访问到f中的test局部变量

    setTimeout(ff, 0); // inner in the f!
    }

    f();
    5
    var lzh = {
    name: 'lzh',
    say: function(something){
    alert(something + this.name);
    }
    }

    var iny = {
    name: 'iny'
    }

    lzh.say.apply(iny, ['hi, I am ']); // 输出 hi I am iny
    6
    var arr = []
    for(var i=0; i<3; i++){
    arr[i] = function(){ console.log(this) }
    }
    var fn = arr[0]

    arr[0]
    /*
    解析: 因为函数是个特殊的对象,所以 arr 相当于 { '0': function(){}, '1': function(){}, '2': function(){}, length:3}
    arr[0]相当于 `arr['0']` 相当于 `arr.0` (当然这种写法不符合规范),所以 arr[0]等价于 arr.0.call(arr), this就是 arr
    */

    fn()
    /*
    解析: 相当于 `fn.call(undefined)`, 所以 fn 里面的 this 是 Window
    */
    7
    var app = {
    container: document.querySelector('body'),
    bind: function(){
    this.container.addEventListener('click', this.sayHello) //点击的时候会执行 sayHello,sayHello 里面的 this 代表 body 对象
    this.container.addEventListener('click', this.sayHello.bind(this)) //点击的时候会执行 sayHello,sayHello 里面的 this 代表 app 对象
    },
    sayHello: function(){
    console.log(this)
    }
    }
    app.bind()

箭头函数中的this

默认指向在定义它时,它所绑定的对象的上一级,而不是执行时的对象, 定义它的时候,可能环境是window

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function foo() {
return () => {
return () => {
return () => {
console.log(this);
};
};
};
}
foo()()()() //window
var f = foo.call({id: 1});
f()()() //{id:1}
var t1 = f.call({id: 2})()();//{id:1}
var t2 = f().call({id: 3})();//{id:1}
var t3 = f()().call({id: 4});//{id:1}

setTimeout中的this

普通函数指向window
箭头函数指向定义的对象
引用函数,指向调用对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
 0、
var obj = {
fn1 : function () {
console.log(this); //obj
},
fn2 : function () {
setTimeout(function () {
console.log(this); //window 匿名函数执行在window环境,找不到宿主对象,所以指向window
},0);
},
fn3: function () {
setTimeout(() => {
console.log(this); //obj 箭头函数创建在obj上
},100);
}
fn4: function () {
var that = this;
setTimeout(function () {
console.log(that) //obj 在setTimeout里面引用obj
console.log(this) //window
});
}
fn5: function () {
var f1 = () => {
console.log(this); // obj f1定义处在obj里面
setTimeout(() => {
console.log(this); // obj 箭头函数定义处在obj里面
})
}
f1();
}
fn6: function () {
var f2 = function () {
console.log(this); // window, f2调用时,没有宿主对象,默认是window
setTimeout(() => {
console.log(this); // window 箭头函数定义在f2确定的window里面
})
};
f2();
}
fn7: function () {
'use strict';
var f3 = function () {
console.log(this); // undefined
setTimeout(() => {
console.log(this); // undefined
})
};
f3();
}
};
obj.fn1();
obj.fn2();
obj.fn3();
obj.fn4();
···

1、
function foo(){
setTimeout(function(){
console.log(this) //window 匿名函数,找不到宿主对象
}, 100);
setTimeout(() => {
console.log(this) //window foo挂载在window对象上
}, 100);
}
foo();
foo.call({id:42}); //window {id:42} foo运行时所在的对象,恰好是箭头函数定义时所在的对象
//call([thisObj[,arg1[, arg2,....]) 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。

2、
function method() {
alert(this.value); // 输出 42 第二个this
}

function Foo() {
this.value = 42;
setTimeout(this.method, 500); // 这里this指向window 第一个this
}

Foo();
//Foo挂载在window上,当执行Foo时,this指向window,Foo里面的value被挂到window,method本来就挂在window上,所以执行this.method就是调用window.method
//method执行,它的this指向window,这时window已经挂上value值42
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
 //其他理解
let app = {
fn1: function(a){
console.log(this) //app
}
fn2(a) {
consoel.log(this) //app
},
fn3: (a)=>{
console.log(this) //window
}
}

app.fn2.call(app)
app.fn3.call( 它的上一级的 this )
1.
var app = {
init() {
var menu = {
init: ()=>{
console.log(this)
},
bind() {
console.log(this)
}
}
menu.init()
/*相当于 menu.init.call(menu 所在的环境下的 this) , 所以 init 里面的 this 也就是 app。
(假设 app.init 也是箭头函数,想想 menu.init 里面的 this 是什么?)
*/
menu.bind()
/*相当于 menu.bind.call(menu),也就是 menu,所以 bind 里面的 this 就是 menu
*/
}
}
app.init()


2.
var app = {
fn1() {
setTimeout(function(){
console.log(this)
}, 10)
},
fn2() {
setTimeout(()=>{
console.log(this)
},20)
},
fn3() {
setTimeout((function(){
console.log(this)
}).bind(this), 30)
},
fn4: ()=> {
setTimeout(()=>{
console.log(this)
},40)
}
}
app.fn1()
app.fn2()
app.fn3()
app.fn4()

var app = {
fn1() {
function fn(){
console.log(this)
}
//过10ms 后执行
//fn.call(undefined) ,所以输出 Window
},
fn2() {
//过20ms 执行箭头函数
//箭头函数里面没资格有 自己的 this,借用 setTimeout 外面的 this,也就是 app
},
fn3() {
// 创建了一个新函数,这个新函数里面绑定了 外面的this,也就是 app
// 20 ms 后执行新函数,输出 this,也就是刚刚绑定的 app
}
fn4: ()=> {
//过40ms 执行箭头函数
//箭头函数里面没资格有 this,用 setTimeout 外面的 this
//setTimeout 所在的 fn4也是箭头函数,没资格拥有自己的 this,借用外面的 this ,也就是 Window
}

应用