前排声明,这真的是写 this,没有什么太多新的东西,就是一个本身对 this 绑定规则的总结,也许后期水平提升会从更深的角度去解释 JavaScript 中的 this 绑定规则。本文从分别从绑定全局对象和绑定具体对象的角度总结了一下 this 的绑定规则。javascript
this 绑定全局对象,分为两种状况:html
这种没什么好说的,全局做用域下调用 this 绑定的是全局对象,例如浏览器中绑定的是 window 对象。java
console.log(this)
复制代码
直接拿上面这段代码在浏览器控制台运行下获得的就是全局对象。数组
直接使用函数名调用函数浏览器
function test () {
console.log(this); // window
}
test();
var test1 = function() {
console.log(this); // window
}
test1();
复制代码
代码传送门app
定义某对象的属性为函数,该属性值被赋值被另外一变量时。dom
var aObj = {
propertyFn: function() {
console.log(this.testName);
},
testName: "aObj"
};
aObj.propertyFn(); // "aObj"
var aFn = aObj.propertyFn;
aFn(); // undefined
复制代码
代码传送门函数
绑定具体对象的状况较多,可总结为如下几种ui
函数做为对象属性被获取并调用时,函数中的 this 绑定的是获取该属性的对象。考虑以下代码this
function test() {
return this.testName;
}
var testObj = {
testName: "testObj",
getTestName: test,
getTestNameFn: function() {
return this.testName;
}
}
console.log(testObj.getTestName()); // "testObj" 函数虽然是在全局做用域下定义的,
// 可是被赋值给了testObj的getTestName属性,且是被做为对象的属性调用的
console.log(testObj.getTestNameFn()); // "testObj"
复制代码
使用 new 关键字调用函数时,该函数会生成并返回以个新的对象,函数中的 this 绑定的生成的新对象。
function Test(name) {
this.name = name;
console.log(this);
}
var s = new Test("s"); // {name: "s"}
function Test1(name) {
this.name = name;
console.log(this);
return true;
}
var s1 = new Test1("s1"); // {name: "s1"}
function Test2(name) {
this.name = name;
console.log(this);
return {};
}
var s2 = new Test2("s2"); // {name: "s2"}
复制代码
上述结果代表,使用 new 调用函数的时候必定会生成一个新对象,且 this 绑定的就是这个新对象,只不过当你在函数中 return 了非 Object 类型的值时,这个对象不会被赋值给你定义的接收变量,这时接收的变量被赋的是函数中使用 return 返回的值。
这里call和apply的做用是相似的,都是函数的实例方法,可为函数指定 this 绑定的对象,二者区别在于 apply 的第二个参数是数组,该数组中的值会以实参形式被传递给调用 apply 的函数,而 call 函数除了第一个参数外的参数均被传递给调用 call 的函数。
function test(param1, param2) {
console.log(this.name, param1 + ", " + param2);
}
var a = {
name: "a"
};
var b = {
name: "b"
}
test.call(a, "aParam1", "bParam2");
test.apply(b, ["bParam1", "bParam2"]);
test();
复制代码
bind函数的做用和以上二者与别很大,其做用是将函数中的 this 绑定对象与指定的对象绑定起来,返回一个函数,每次调用返回的函数时,其 this 都是绑定的指定对象。
function test() {
console.log(this.name);
}
var a = {
name: "a"
}
var bindTest = test.bind(a);
bindTest(); // "a"
var b = {
name: "b",
getName: bindTest
}
b.getName(); // "a"
var c = new bindTest(); // undefined
bindTest.call(b); // "a"
复制代码
从上面的示例代码能够看出,函数和指定对象被绑定后使用 new 关键字是绑定失效,在以上示例中绑定函数中的 this 绑定的是一个新建立的对象实例,且该对想的构造函数时test函数。由此也可得出,this 绑定场景同时出现的状况下 new 的优先级是高于调用 bind 函数的优先级的。
关于箭头函数中 this 绑定,MDN 中的说法是箭头函数是没有本身的 this 的,其 this 是从其做用域链上层做用域继承而来的。那么怎么理解呢?下面上代码:
let arrowFn = () => {console.log(this === window)};
arrowFn(); // true
let a = {
name: "a",
getSelf: arrowFn
};
a.getSelf(); // true
let b = {
name: "b"
}
arrowFn.call(b); // true
复制代码
以上代码是箭头函数直接在全局做用域下定义的状况,那么其做用域链上层就是全局做用域,而在浏览器中全局做用域 this 绑定的值是 window 。因为 JavaScript 中的做用域是静态做用域,那么箭头函数在全局做用域中定义时便已经能够肯定其 this 就是 window 了,并且后面的该箭头函数做为对象属性值被调用,仍是使用 call 显示指定 this 其 this 均为改变。而非箭头函数的画风是这样的:
let fn = function() {
console.log(this === window);
}
fn(); // true
let a = {
name: "a",
getSelf: fn
};
a.getSelf(); // false
let b = {
name: "b"
}
fn.call(b); // false
复制代码
那么是否是一旦箭头函数被定义了,其 this 的绑定就已经被肯定了呢?
let createArrowFn = function() {
return () => {console.log(this)};
}
let a = {
name: "a",
getSelf: createArrowFn
};
let aArrow = a.getSelf();
aArrow(); // 对象a
let b = {
name: "b"
}
var bArrow = createArrowFn.call(b);
bArrow(); // {name: "b"}
复制代码
上面代码两次 this 打印的结果是不同的,那么是否是就推翻了箭头函数一旦被定义,其 this 就已经肯定了的结论。其实否则,这里箭头函数的是上层做用域是createArrowFn这个函数的做用域,这个函数做用域中的 this 会随着调用场景的不一样发生发生变化,因此继承其做用域绑定 this 的箭头函数中的 this 天然也会发生改变了。其实箭头函数中的 this 能够这么理解,至关于将函数的上层做用域的 this 用一个变量保存下来,而后在其子函数中使用它。
let fn = function() {
var _this = this;
return function() {
console.log(_this);
}
}
let a = {
name: "a",
getSelf: createArrowFn
};
let aArrow = a.getSelf();
aArrow(); // 对象a
let b = {
name: "b"
}
var bArrow = createArrowFn.call(b);
bArrow(); // {name: "b"}
复制代码
在理解箭头函数中的 this 时只需理解其被定义时所在做用域的 this 绑定的是什么就能够了。
先说明不论是事件监听器仍是事件处理器中 this 绑定的都是当前触发该事件的节点,即绑定了该事件的元素节点。
这里主要是区分下事件监听器和事件处理器,事件处理器实际上是指 html 标签的 on... 属性定义的函数,好比 onclick="function() {}",固然也能够在 JavaScript 中去设置该属性,事件处理器的特色是其只能有一个,由于是 html 标签属性因此能够覆盖。
事件监听器是指使用addEventListener函数注册的事件回调函数,可同时注册多个。
在讨论 JavaScript 中 this 的绑定值时,其实就是几种状况:
以上总结仅仅为粗浅的不一样场景下 this 的绑定值的总结,没有从更深的层次(好比ES标准中的定义)去讨论,主要我的
时间水平有限,因此大佬请忽略。若有错误欢迎各位指正,不胜感激。