写在前面
这里是小飞侠Pan🥳,立志成为一名优秀的前端程序媛!!!
本篇文章收录于我的专栏:前端精进之路
同时收录于我的github前端笔记仓库中,持续更新中,欢迎star~
了解this
this 就是一个指针,指向调用函数的对象。
际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用。
一.绑定方式
this
thisundefined
独立函数调用
obj.foo()foothisobjcall()apply()thisfoo.call(obj)newthisthis
2.根据函数的调用方式的不同,this 会指向不同的对象:
fun();window.fun();
二.一些函数的this分析
1.setTimeout
setTimeout(function () {
console.log(this); //Window
}, 1000);
2.div的点击
<div class="box">123</div>
<script>
const boxDiv = document.querySelector(".box");
boxDiv.onclick = function () {
console.log(this);
//<div class="box">123</div>
};
</script>
3.数组的forEach
var names = ["abc", "cba", "nba"];
names.forEach(function (item) {
console.log(item, this);
});
var names = ["abc", "cba", "nba"];
names.forEach(function (item) {
console.log(item, this);
}, "abc");
三.this绑定优先级规则
1.默认规则的优先级最低
毫无疑问,默认规则的优先级是最低的,因为存在其他规则时,就会通过其他规则的方式来绑定this
2.显示绑定优先级高于隐式绑定
call(),apply()
var obj = {
name: "obj",
foo: function() {
console.log(this);
}
}
obj.foo.call('abc') //[String: 'abc']
obj.foo.apply('abc')//[String: 'abc']
bind()
function foo() {
console.log(this);
}
var obj = {
name: "obj",
foo: foo.bind("aaa")
}
obj.foo() //[String: 'aaa']
3.new绑定优先级高于隐式绑定
new
var obj = {
name: "obj",
foo: function() {
console.log(this);
}
}
var f = new obj.foo() //foo {}
newfooobjobj
4.new绑定优先级高于bind
new绑定和call、apply是不允许同时使用的,所以不存在谁的优先级更高
new绑定可以和bind一起使用,new绑定优先级更高
function foo() {
console.log(this);
}
var bar = foo.bind("aaa")
var obj = new bar() //foo {}
5.this规则之外– 忽略显示绑定
apply/call/bind:当传入null/undefined时,自动将this绑定成全局对象
function foo() {
console.log(this);
}
foo.apply("abc"); //String:"abc"
foo.apply({}); //Object
foo.apply(null); //window
foo.call(undefined); //window
var bar = foo.bind(null);
bar(); //window
6.this规则之外- 间接函数引用
function foo() {
console.log(this);
};
var obj1 = {
name: "obj1",
foo: foo
};
var obj2 = {
name: "obj2"
};
obj1.foo(); //obj1
(obj2.foo = obj1.foo)(); //window
7.箭头函数
简介
箭头函数不会绑定this、arguments属性;
箭头函数不能作为构造函数来使用(不能和new一起来使用,会抛出错误);
箭头函数简写:
1.如果函数执行体只有返回一个对象, 那么需要给这个对象加上()
var bar = () => ({name: "ha", age: 17})
2.如果函数执行体中只有一行代码, 那么可以省略大括号
nums.forEach(item => console.log(item))
this绑定规则
箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined。
var name = "ha"
var foo = () => {
console.log(this);
}
foo() //window
var obj = {foo: foo}
obj.foo() //window
foo.call("bac") //window
不论通过什么方式调用,this 绑定的是最近一层非箭头函数的 this
应用场景
var obj = {
data: [],
getData: function() {
setTimeout(function() {
var result = ["abc","cba","nba"]
this.data = result
},2000)
}
}
obj.getData()
console.log(obj.data);//Array(0)
//此时obj拿不到result数组,
//因为this指向出了问题:setTimeout的this指向是window,此时obj的data仍是空数组
改进:
var _this = this
var obj = {
data: [],
getData: function() {
var _this = this
setTimeout(function() {
var result = ["abc","cba","nba"]
_this.data = result
},1000)
}
}
obj.getData()
console.log(obj);
使用箭头函数:
var obj = {
data: [],
getData: function() {
setTimeout(() => {
var result = ["abc","cba","nba"];
this.data = result;
},1000)
}
}
obj.getData();
console.log(obj);
/*data: Array(3)
0: "abc"
1: "cba"
2: "nba"
length: 3
*/
如果getData也是一个箭头函数,那么setTimeout中的回调函数中的this指向谁呢?
window
var obj = {
data: [],
getData: () => {
setTimeout(() => {
console.log(this); //window
}, 1000);
},
};
obj.getData();
四.面试题
var name = "window"
var person = {
name: "person",
sayName: function() {
console.log(this.name);
}
}
function sayName() {
var sss = person.sayName;
sss();//window
person.sayName();//person
(person.sayName)();//person:这里的括号加与不加都是一样的
(b = person.sayName)();//window:间接函数引用
}
sayName()
总结
定义对象不产生作用域,对象不是作用域,函数是作用域
var name = "window"
var person1 = {
name: "person",
foo2: () => console.log(this.name);
foo4: function() {
return () => {
console.log(this.name)
}
}
}
var person2 = {name: 'person2'}
person1.foo2()//window
person1.foo2.call(person2)//window
person1.foo4()()//person1
person1.foo4.call(person2)()//person2
person1.foo4().call(person2)//person1
var name = "window"
function Person(name) {
this.name = name
this.foo2 = () => console.log(this.name)
this.foo4 = function() {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo2()//person1
person1.foo2.call(person2)//person1
person1.foo4()()//person1
person1.foo4.call(person2)()//person2
person1.foo4().call(person2)//person1
检验自己是否真正理解: