嘿,加油
在其他面向对象编程中,this 一般会出现在类的方法里,但是在js中,this更灵活,无论是它出现的位置还是它代表的含义。首先this在全局里指向window, 但是,开发中很少直接在全局作用于下去使用this,通常都是在函数中使用,在之前文章里说过,当我们函数调用时,会创建一个执行上下文,这个上下文记录着函数的调用栈,AO对象,还有其他,当然还记录着一个很重要的东西,this
function foo() {
console.log(this);
}
// 1.调用方式一:直接调用;
foo(); //window
// 2.调用方式二:将foo放到一个对象中,再调用
var obj = { name: "why", foo2: foo };
obj.foo2(); //obj对象
// 3.调用方式三:通过ca1l/apply调用
foo.call("abc"); // String {"abc"子对象}
根据这个案例,我们可以发现
那么this到底是怎么样的绑定规则呢?
当独立函数调用时,JavaScript会默认给this绑定一个值: windows
独立的函数调用我们可以理解成 函数没有被绑定到某个对象上进行调用
另外一种比较常见的调用方式是通过某个对象进行调用,也就是它的调用位置中,是通过某个对象发起的函数调用。
隐式绑定有一个前提条件:
如果我们不希望在 对象内部 包含这个函数的引用,同时又希望在这个对象上进行强制调用,该怎么做呢?
JavaScript所有的函数都可以使用call和apply方法(这个和Prototype
有关)。
这两个函数的第一个参数都要求是一个对象,这个对象的作用是什么呢?就是给this准备的。
在调用这个函数时,会将this绑定到这个传入的对象上。
因为上面的过程,我们明确的绑定了this指向的对象,所以称之为 显示绑定。
JavaScript中的函数可以当做一个类的构造函数来使用,也就是使用new关键字。
使用new关键字来调用函数是,会执行如下的操作:
我们通过一个new关键字调用一个函数时(构造器),这个时候this是再调用这个构造器时创建出来的对象,this=创建出来的对象,这个绑定过程也称为new绑定
//比如夏夏有个充电宝,它可以使用charge这个充电宝给自己的手机电池phoneBattery任意充电
const xiaxia={
name:'xiaxia',
phoneBattery:70,
charge:function (level){
this.phoneBattery=level
}
},
xiaxia.charge(100)
//但是haha手机没电了,也不想买充电宝,但是它可以借xiaxia的
const haha={
name:'haha',
phoneBattery:40,
},
xiaxia.charge.call(haha,100)
//方便演示apply 的用法,假设充电宝必须冲两次
const xiaxia={
name:'xiaxia',
phoneBattery:70,
charge:function (level,newlevel){
this.phoneBattery=level+newlevel
}
}
// 如果使用 call 方式
xiaxia.charge.call(haha,20,50)
// 如果使用 apply 方式
xiaxia.charge.apply(haha,[20,50])
// bind 方式,其实是借了充电宝,但不是立即使用,而是过一会使用
const hahaMethods=xiaxia.charge.apply(haha)
haha.hahaMethods(20,50)
有些时候,我们会调用一些JavaScript的内置函数,或者一些第三方库中的内置函数。这些内置函数会要求我们传入另外一个函数; 我们自己并不会显示的调用这些函数,而且JavaScript内部或者第三方库内部会帮助我们执行;这些函数中的this又是如何绑定的呢?
可以通过上图发现,对于内置函数,他们的this情况,比如对于setTimeout ,他是一个独立执行,默认绑定;看第四张图,它有提示thisArg ,其实是说我们可以自己更改他的this指向,比如第三张图,如果我们传入第二个参数为obj,就把他的this执行为obj了
学习了四条规则,接下来开发中我们只需要去查找函数的调用应用了哪条规则即可,但是如果一个函数调用位置应用了多条规则,优先级谁更高呢?
var obj={
name:'obj'
foo:function(){
console.log(this)
}
}
// 当这个有显示绑定(call)和隐式绑定(obj)时,发现他的this指向为 abc
// 说明显示绑定优先级高于隐式绑定
obj.foo.call('abc')
var obj={
name:'obj'
foo:function(){
console.log(this)
}
}
// 虽然这个指向指向的是 abc,但是并不能体现 显示绑定优先级高于隐式绑定
// 因为现在执行的是 obj 的返回的函数,绑定到abc上
// 当foo2执行时 与obj其实是没关系的,只是执行的时候引用了而已
var foo2 = obj.foo.bind('abc')
foo2()
function foo(){
console.log(this)
}
var obj={
name:'obj'
foo:foo.bind('aaa')
}
obj.foo() //这样会更明显 指向的是aaa
var obj={
name:'obj'
foo:function(){
console.log(this)
}
}
var f = new obj.foo() //指向的是foo 说明new的高于隐式
不管函数在什么位置声明,在内存中都是在堆内存中单独分配的空间,得到该函数地址的变量都可以对函数进行调用,所以函数中的this指向与调用位置无关,也就是谁调用就指向谁
apply / call /bind : 当传入 null / undefined 时, 那么这个显示绑定会被忽略,使用默认规则
function foo(){
console.log(this)
}
foo.apply('abc')
foo.apply({})
foo.apply(null)
foo.apply(undefined)
箭头函数并不绑定this对象,那么this引用就会从上层作用于中找到对应的this