this
首先,必须记住一点。this的指向是在函数执行的时候才能确定,this的最终指向的是最终调用它的对象
先来个例子1;
function test(){
let name = 'kobe'
console.log(this.name) //undefined
console.log(this) //window
}
test()
上述代码就可以证明this指向的是调用它的对象 上述代码在全局下 this指向的是window
例子1-1
function test(){
let name = 'kobe'
console.log(this.name) //undefined
console.log(this) //window
}
window.test()
例子1-1
证明了全局下的函数执行this指向window
例子2
let obj = {
name:'kobe',
fn(){ console.log(this.name)}
}
obj.fn() //kobe
例子2中的this指向对象obj 因为调用这个函数是由obj这个函数调用的。这里指向开头说的结论,就是开头黑黑的那句话。
但是下面的例子会推翻该结论
例子3(看标注为第二份的代码) (例子三这里插个题外话本来是用第一份做示例的)
第一份
let obj = {
name:"kobe",
fn(){
console.log(this.name);
}
}
window.obj.fn(); //发现fn显示未定义 其实是let声明的对象不挂载在window上
第二份
var obj = {
name:"kobe",
fn(){
console.log(this.name);
}
}
window.obj.fn(); //kobe
例子3推翻了前面的结论 明明是window(window上没有name属性)调用了该函数 怎么会打印kobe。其实this指向的是 在函数调用的时候 层级离它最近的对象
例子3-1
let obj = {
name:"kobe",
obj1:{
name:'curry',
fn(){
console.log(this.name);
}
}
}
obj.obj1.fn() // curry 这里打印的是obj1的name
let obj = {
name:"kobe",
obj1:{
fn(){
console.log(this.name);
}
}
}
obj.obj1.fn() // undefined 这里打印的是obj1的name
总结 分为三种情况
1、如果一个函数中有this,但是它没有被上一级的对象所调用那么this指向的就是window(在严格模式中 为undefined)
2、如果一个函数中有this,这个函数有被上一级的对象调用,那么this指向的就是上一级的对象
3、如果一个函数中有this,这个函数是在层级较深的对象中定义的方法,this指向的也只是调用它的时候的上一级的对象。
例子4
let obj = {
name:'kobe',
obj1:{
name:'curry',
fn(){
console.log(this.name)
console.log(this)
}
}
}
let fn = obj.obj1.fn
fn() // 会打印undefined 和 window
由于例子4是将obj1内的函数取出放在 fn中 所以在当直接执行的时候是在全局下执行的 这里的this指向的是window
构造函数中的this
例子1
function Fn(){
this.name = "kobe"
}
let a = new Fn();
console.log(a.name) //kobe
在new 的过程中相当于 复制了一份Fn到对象a里面,此时仅仅只是创建,没有执行 用a.name的时候代表条用这个函数的对象是a,this就指向a,由于复制了一份Fn到对象a中所有 对象a中有name
例子2(在构造函数中当遇到return的时候)
function fn()
{
this.name = 'kobe';
return {name: 'curry'};
}
let a = new fn();
console.log(a.name); //curry
function fn()
{
this.name = 'kobe';
return function(){};
}
let a = new fn();
console.log(a.name); //undefined
function fn()
{
this.name = 'kobe';
return 1;
}
let a = new fn();
console.log(a.name); //kobe
function fn()
{
this.name = 'kobe';
return undefined;
}
let a = new fn();
console.log(a.name); //kobe
上述4个例子说明 在构造函数中 this指向的就是new 的时候构造函数返回的对象(除了null之外虽然null也 是对象 比较特殊) 如果不是对象那么this还是指向函数的实例
接下来就可以折腾call,apply,bind了
在需要指定this指向的情况下,会出现这写问题
问题场景我需要条用b调用a中的方法并且用到a中的属性
let a ={
name:'kobe',
fn(){
console.log(this.name)}
}
let b =a.fn
b() //undefined
显然这样是不行的可以用到call
let a ={
name:'kobe',
fn(){
console.log(this.name)}
}
let b =a.fn
b.call(a) //kobe
通过call方法将this指向从window改为a对象
1、call方法之后还可以添加方法的对应参数
let a ={
name:'kobe',
fn(a,b){
console.log(`${this.name}:${a+b}`)}
}
let b =a.fn
b.call(a,1,2) // kobe 3
2、apply方法和call类似就是传递参数的时候是用数组传的
let a ={
name:'kobe',
fn(a,b){
console.log(`${this.name}:${a+b}`)}
}
let b =a.fn
b.apply(a,[1,2]) // kobe 3
如果call和apply的第一个参数写的是null,那么this指向的是window对象
let a ={
name:"kobe",
fn() {
console.log(this.name)
console.log(this)
}
}
let b = a.fn
b.apply(null) // undefined window
3、bind()
bind()方法和call、apply方法有些不同,但是都可以改变this的指向
let a ={
name:"kobe",
fn(a,b) {
console.log(`${a+b}`)
console.log(this.name)
console.log(this)
}
}
let b = a.fn
b.bind(null)
b.bind(null)(1,2) //3 undefiend window
区别在于bind改变指向后不会立即执行 而是一个函数 还需要调用一下才行
所以用bind改变this的指向 函数不用立即执行 而是想在哪用在哪用 传递参数在调用的时候的括号里传