开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情” his指向问题是js中的一个重要的问题,this是js中的一种函数复用机制,允许通过this的方式使用不同的上下文中的变量以及函数。本文将分别从原理层,表现层和应用层三个方面一步一步对相关知识进行总结。
this指向
js指向的核心点在于this指向并不取决于定义,而是取决于调用。this的指向就是判断调用对象,即函数执行的主体。根据函数定义方式的不同可以大致分为以下4中调用方式
- 对象调用(隐式绑定):对象调用方法时,方法内的this指向正在调用方法的对象本身
- 特殊调用(显示绑定):通过call()/apply()/bind()明确的制定this的绑定对象
- 函数调用和不存在函数中的this调用(默认绑定):当单独使用 this,不依附于任何函数或者对象时,指向全局对象。函数进行独立调用不依托于任何对象和不存在任何修饰符时指向window,this指向全局对象,注意严格模式问题(严格模式全局的this指向的是undefined)
- 构造函数调用(new):指向构造函数生成的对象
// 函数独立调用
function foo(){
console.log(this.a)
}
var a = 2
foo() // 2
// 更复杂一点的例子
var name = "windowsName";
var a = {
name: null,
// name: "Cherry",
fn: function () {
console.log(this.name); // windowsName
}
}
var f = a.fn;
f();// 上一步将a中的fn方法给了变量f在f()执行时并没有调用的对象所以指向window对象输出结果为undefined
var name = "windowsName";
function fn() {
var name = 'Cherry';
innerFunction();
function innerFunction() {
console.log(this.name); // windowsName
}
}
fn()
// 这段代码同样是因为innerFunction()函数内部定义的方法,但是无调用的对象,则this指向window
根据以上逻辑,在实际代码开发中this存在以下几种可能
- 全局下的this指向windos对象:当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。
- 对象方法中的this:谁调用方法,this就指向谁(对象方法中传入一个函数时,相当于定义在全局的函数传递在此位置,所以传入函数的this同样是指向window的 ) 将一个函数作为参数传递给另一个函数,当函数执行时这个函数进行执行,这样的函数叫做回调函数(表达时的方式可以是取名函数a和函数b)
- 构造函数中的this:指向实例化对象
- 箭头函数中的this:this直接指向箭头函数定义时的作用域,与调用时的作用域无关,外部的this指向就是箭头函数中this的指向,使用call/apply等任何的方式都无法改变箭头函数中this的指向
- 自执行函数:函数中的this是指向windos或undefined(普通模式和严格模式)
改变this指向的方法
call()/apply()/bind()都可以对this的指向进行修改,具体区别如下
两者都是函数原型上的方法,函数通过调用这两种方法可以实现对于this指向的修改相比之下多参数时,call的性能要好一些
call和apply的功能是完全一样的,只是第二个参数不一样;
call可以接收无限多个参数,apply只接收俩参数,并且第二个参数只能是argument。
“而它们同样的第一个参数,就是新的this指向!”
call()/apply()是this指向的借用是临时性的修改,而bind函数会返回一个函数,然后我们想要调用的时候才会执行,在这个函数中是对this指向永久性的更改
var obj1 ={
numA:1,
numB:2,
add:function(){
console.log(this.numA + this.numB)
}
}
obj1.add(); //打印出obj1.numA和obj1.numB的和,即3
var obj2 = {
numA:3,
numB:4
}
//用call借:
obj1.add.call(obj2); //打印出obj2.numA和obj2.numB的和,即7;
//用apply借:
obj1.add.apply(obj2); //打印出obj2.numA和obj2.numB的和,即7;
obj1.add()
//call和apply在于参数接受方式的不同
obj1.add.call(obj2,3,4);
obj1.add.apply(obj2,[3,4]);
//bind()函数的执行
var obj1 = {
name: "小明",
fn1: function (val) {
console.log(this.name);
}
}
var obj2 = {
name: "小红",
fn2: function () {
console.log(this.name);
}
}
var newfn3 = obj1.fn1.bind(obj2); //此时函数并不会执行,bind 是创建一个新的函数,我们必须要手动去调用
obj1.fn1()
newfn3();
obj1.fn1()
由以上代码可以看出call()与apply()的效果完全一致,且this指向的改变只发生在obj1.add.call(obj2)语句执行时,语句执行完之后并不会改变原有对象obj1中的this指向,由此可见改变this是借用的设计思路。