携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
场景1、 函数直接调用时
- this指向全局变量,node就是global,js就是window,
- 严格模式下就是undefined
举个例子
- 最普通的函数调用
function test () {
console.log(this)
}
test() ; // undefined 或 Window(Object)
- 嵌套函数调用
function son () {
console.log(this)
}
function father () {
son(); // 一样的,只要是普通的方法调用嵌套多少层都是这样
}
father(); // undefined 或 Window(Object)
场景2、 函数被其他对象调用时候
例如obj.fun()
,这里的函数fun
被obj
点了,那么this
就是指向obj
这个对象,要注意是执行的时候被谁点,不是定义的时候,因为操作访问符访问方法时,方法会隐式绑定前面的对象
举例子
- 调用对象里面的函数
const father = {
type: 'person',
buy: function() {
console.log(this)
}
}
father.buy(); // {type: 'person', buy: ƒ} 指向了fahter这个对象
- 调用对象里面的对象的函数
const father = {
type: 'person',
cat: {
type: 'animal',
buy: function() {
console.log(this)
}
}
}
// 注意这里是.的前面,也就是cat这个对象,而不是father
father.cat.buy(); //{type: 'animal', buy: ƒ}
- 监听函数的时候
const father = {
buy: function() {
console.log(this)
}
}
window.addEventListener('scroll', father.buy); // undefined 或 Window(Object), 因为执行的时候是自然执行的
// 这个时候你是不是以为指向的
// 上面的函数翻译过来
window.addEventListener('scroll', function() {
console.log(this)
});
// 在执行的时候其实就是自然执行,并没有被谁.fun这样执行,所以判去场景1,直接调用场景
// 这也印证了上面说的是执行时候的.(点),而不是定义时候的.(点)
- 奇怪的语法 var a = (1, 2) 会返回第二个值
const father = {
buy: function() {
console.log(this)
}
}
// 这里也是上面的监听例子,一样,只是障眼法,实际是属于场景1的,自然执行调用
(1, father.buy)(); // undefined 或 Window(Object), 因为执行的时候是自然执行的
\
场景3、 new一个实例的时候
this就是指向new出来的实例,因为:
new的过程
- 在内存中创建一个新的对象
- 把这个对象的prototype指向这个构造函数的prototype
- 然后把这个this指向新对象的this
- 然后执行里面的代码赋值
- 如果return非空对象,则正常return;如果没有return,则返回新创建的这个对象
- new 实例
function Person(aa) {
console.log(this)
}
let teacher = new Person('aa'); // Person {} 这里会打印出构造函数,实际上this就是指向新实例的,可以参考可以new过程发生的事情
场景4、call,apply,bind
这个三个函数可和之前的三个场景不同,这里可以去改变this的指向,要看最终他们究竟调用这三个函数把this的指向指去了哪里
call,apply
- 改变this的指向,接受两个参数,一个是this的指向,一个是接受参数(call是接受一个一个参数,apply是接受一个数组作为参数)
- 绑定了函数的this之后立刻执行
例子
- call,apply
const obj = {name: 'one'}
function test (first, second) {
console.log(first, second);
console.log(this)
}
test.call(obj, 1, 2); // 1 2 {name: 'one'}
test.apply(obj, [1, 2]); // 1 2 {name: 'one'}
bind
- 给你返回一个绑定了this的函数
- bind直接传参不能动态传参
- bind
// eg one
const obj = {name: 'one'}
function test (first, second) {
console.log(this)
}
const fun = test.bind(obj, 1, 2);
fun(); // 1 2 {name: 'one'}
场景5、箭头函数
- this指向离我的定义时候非箭头函数的上下文
- apply,call,bind无效了
例子
- 箭头函数普通场景
function one () {
console.log(this); // {name: 'test', one: ƒ}
// one才是arrow的定义时上下文
const arrow = () => {console.log(this)} // {name: 'test', one: ƒ}
function two () {
console.log(this); // Window
arrow();
}
two();
}
const test = {name: 'test'};
test.one = one;
test.one();
解释一下上面的例子 :
- 首先我们找到箭头函数 arrow
- arrow 定义时候最近的非箭头函数就是 one,就是指向one的this的指向
- one被赋值进了一个test对象的one属性里面
- test.one()的时候,one是指向.(点)他的对象,也就是test对象
- 那么arrow也是指向test对象
- call无效了
const arrow = () => {console.log(this)};
const obj = {name: 'joe'};
arrow.call(obj); // window 绑定也没有效果
解释一下上面的例子
- 这里看似arrow使用call指向了this
- 但是call,apply,bind对箭头函数无效的
- 所以arrow还是指向定义时候的上一层非箭头函数的this,那么就是整个代码片段了,也就是window了
结尾
这样可以比较快速的分辨出来this的指向,但是实际比较深入我也懵懵懂懂,但是这个识别5个场景来快速辨别我是从直播课听的,感觉还是有点用,就分享一下!!!以后再深入学习。