js中this的“终极三问”

31次阅读

共计 2897 个字符,预计需要花费 8 分钟才能阅读完成。

this 是什么?
this 本质是一个绑定,在函数被调用时建立。它的指向是完全由函数被调用的调用点来决定的。

function baz() {
console.log(this);// 因为 baz 函数的调用点在全局作用域,所以 this 指向全局变量
}
baz();// 这里就是 baz 函数的调用点

this 存在的意义
在函数体内部指代函数当前的运行环境。从而实现干净的 API 设计和更容易的复用。

this 的使用

top-level scope
1) In browsers, the top-level scope is the global scope. This means that within the browser var something will define a new global variable.In Node.js this is different. The top-level scope is not the global scope; var something inside a Node.js module will be local to that module.
2) 但是在 Node REPL 下,与浏览器的行为保持一致(timers 除外)
In browsers
var that = this;
setTimeout(function() {
console.log(this);//window
}, 0);
Node REPL
var that = this;
setTimeout(function() {
console.log(this);//Timeout {…}
}, 0);
setInterval 结果相同

严格模式下
指定的 this 不在被封装为对象,而且如果没有指定 this,则 this 的值为 undefined
sloppy mode
function foo() {
console.log(this);
}
foo.apply(“test”); //==>String {“test”}0: “t”1: “e”2: “s”3: “t”length: 4…[[PrimitiveValue]]: “test”
strict mode
function foo() {
“use strict”;
console.log(this);
}
foo.apply(“test”); //==>test

调用方法时没有明确对象,this 指向全局对象
sloppy mode
In browsers,this 指向 window
console.log(this);//window
Node REPL, this 指向 global
console.log(this);//global
strict mode
In browsers,this 指向 window
“use strict”;
console.log(this);//window
Node REPL, this 指向 global
“use strict”;
console.log(this);//global

匿名函数执行时当前对象是全局对象
sloppy mode
In browsers,
(function() {
console.log(this);//window
})();
Node REPL
(function() {
console.log(this);//global
})();
strict mode
In browsers,
(function() {
“use strict”;
console.log(this);//undefined
})();
Node REPL
(function() {
“use strict”;
console.log(this);//undefined
})();

强制一个函数调用使用某个特定对象作为 this 绑定, 而不在这个对象上放置一个函数引用属性 就 this 绑定的角度讲,call(..) 和 apply(..) 是完全一样的 call
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
foo.call(obj); //==>2 强制函数 foo()的 this 指向 obj
apply
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
foo.apply(obj); //==>2 强制函数 foo()的 this 指向 obj

bind 返回一个硬编码的新函数,它使用你指定的 this 环境来调用原本的函数
function foo(something) {
console.log(this.a, something);
return this.a + something;
}
var obj = {
a: 2
};
var a = 6;
var bar = foo.bind(obj);// 使用 obj 作为 this 环境调用 foo()
var b = bar(3); // 2 3
console.log(b); // 5
var test = bar.bind(window);//2 3
console.log(test(3)); // 5

传递 null 或 undefined 作为 call、apply 或 bind 的 this 绑定参数,那么这些值会被忽略掉。
sloppy mode
function foo() {
console.log(this);
}
var obj = {};
foo.call(null);//window or global
foo.apply(null);//window or global
var bar = foo.bind(null);
console.log(bar());//window or global
strict mode
“use strict”;
function foo() {
console.log(this);
}
var obj = {};
foo.call(null);//null
foo.apply(null);//null
var bar = foo.bind(null);
console.log(bar());//null

new
将新构建的对象被设置为函数调用的 this 绑定
function foo(a) {
console.log(this);
this.a = a;
}
var bar = new foo(2);// 构建了一个新的对象 (foo {a: 2}) 并把这个新对象作为 foo(..) 调用的 this
console.log(bar); //foo {a: 2}
console.log(bar.a); // 2

arrow functions
箭头函数从封闭它的(函数或全局)作用域采用 this 绑定
function foo() {
// 返回一个箭头函数
return (a) => {// 箭头函数在词法上捕获 foo() 被调用时的 this(obj1)
// 这里的 `this` 是词法上从 `foo()` 采用的
console.log(this.a);
};
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call(obj1);
bar.call(obj2); //2

Refer:
https://github.com/CuiFi/You-Dont-Know-JS-CN
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this

正文完
 0