《你不知道的JS(中卷)》this详解
Posted enmac
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《你不知道的JS(中卷)》this详解相关的知识,希望对你有一定的参考价值。
二、this全面解析:
? 这一章将详细分析this的各种绑定方式。
一)、调用位置:
? 要理解绑定方式,首先需要理解 调用位置。
? (调用位置 o 调用栈(为了到达当前执行位置所调用的所有函数))
function baz() {
// 调用栈: baz
// 调用位置: 全局作用域
console.log("baz");
bar();
}
function bar() {
// 调用栈: baz -> bar
// 调用位置: baz函数中
console.log("bar");
foo();
}
function foo() {
// 调用栈: baz -> bar -> foo
// 调用位置: bar函数中
console.log("foo");
}
baz();
二)、绑定规则:
1、默认绑定:
? 可以看作是当其他绑定规则无法应用时的默认规则:this指向全局作用域(use strict时为undefined)
2、隐式绑定:
? 应用于调用位置具有上下文对象时。
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
尽管在JS中不能说obj对象拥有foo函数。但是在上列中调用位置会使用obj上下文调用函数,在函数调用时可以说obj“拥有”这个函数。
- 对象属性引用链中只有栈顶会影响调用位置。
引用丢失:
var obj = {
a: 2,
foo: foo
};
// bar是一个obj.foo的引用,但实际上是foo的引用,因此此时适用于默认绑定
var bar = obj.foo;
var a = "oops, global";
bar(); // oops, global
- 引用丢失常发生在回调函数中,如果给回调函数传obj.foo,实际上函数引用的就是foo。
3、显式绑定:
call(), apply()方法,将对象绑定到this,接着在调用函数时指定这个this。
function foo() {
console.log(this.a);
}
var obj = {
a:2
};
foo.call(obj); // 2
- 因为可以直接指定this的绑定对象,因此被称为显式绑定。
但是显式绑定仍然无法解决 丢失绑定问题。
1)、硬绑定:
// ...
var bar = function() {
foo.call(obj);
}
setTimeout(bar, 100000);
创建一个包裹函数,传入所有的参数并返回接收到的所有值。
-
由于硬绑定非常常用,因此ES5中内置了bind方法:
var bar = foo.bind(obj);
2)、API调用的“上下文”:
? 第三方库的许多函数,以及JS语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被称为“上下文”(context),其作用和bind一样,确保你的回调函数使用指定的this。
function foo(el) {
console.log(el, this.id);
}
var obj = {
id: "awesome";
};
// 调用foo(...)时把this绑定到obj
[1, 2, 3].forEach(foo, obj);
// 1 awesome 2 awesome 3 awesome
4、new绑定:
? 在传统的面向对象语言中,new是构造函数的特殊方法。而在JS中,构造函数只是一些使用new操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。更不是特殊的函数类型,只是被new操作符调用的普通函数。
? 使用new调用函数时自动执行以下操作:
- 创建(构造)一个全新的对象。
- 新对象执行[[原型]]连接。
- 新对象绑定到函数调用的this。
- 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2
三)、优先级:
(new>显式>隐式>默认)
四)、绑定例外:
1、被忽略的this:
? 将null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
2、间接引用:
function foo() {
console.log(this.a);
}
var a = 2;
var o = {a: 3, foo: foo};
var p = {a: 4};
o.foo() // 3
// 赋值表达式的返回值是foo的引用,因此调用位置为foo(),因此应用默认绑定
(p.foo = o.foo); // 2
3、软绑定:
五)、this词法:
箭头函数:
? 箭头函数不适用于this的规则,而是由外层(函数或者全局来决定this)。
function foo() {
return (a) => {
console.log(this.a);
};
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
};
var bar = foo.call(obj1);
bar.call(obj2); // 2
箭头函数可以像bind(..)一样确保函数的this被绑定到指定对象,此外,它用更常见的词法作用域取代了传统的this机制。
- this风格与词法作用域不应该混用!
以上是关于《你不知道的JS(中卷)》this详解的主要内容,如果未能解决你的问题,请参考以下文章