前言
今天我们来聊一聊JS中的“this”!JavaScript 中的 this 是一个特殊关键字,它可以引用当前执行上下文中的对象。让我们先看下面一段代码:
function identify(context) {
return context.name.toUpperCase()
}
function speek(context) {
var greeting = "Hello,I'm " + identify(context);
console.log(greeting);
}
var me = {
name: "Tom"
}
console.log(speek(me));
再看另一段代码:
function identify() {
return this.name.toUpperCase()
}
function speek() {
var greeting = "Hello,I'm " + identify.call(this);
console.log(greeting);
}
var me = {
name: "Tom"
}
speek.call(me)
看出区别了吗?没错!虽然他们输出的结果是一样的,都是:Hello,I'm TOM,但是后者通过使用this更方便地进行了指向,简化了我们的代码,这就是this的作用。
正文
this
this用来代指,也就是用来简化代码——这是它的用处,那this有什么特点呢?
function foo() {
var a = 2;
this.bar()
}
function bar() {
var b = 3
console.log(this.a);
console.log(this.b);
}
foo()
正常我们想要的结果应该是2和3,但这里输出的结果都是undefined,这是为什么呢?这里的两个this都指向了全局,所以拿不到函数中的a和b。this不能引用一个词法作用域中的内容——这就是this的特点。
this的绑定规则
默认绑定 --- 函数在哪个词法作用域里生效,this就指向哪里。也可以简单地记为:只要是默认绑定,this就是默认指向全局。
var b = 2
function foo() {
var b = 1
function bar() {
baz()
}
function baz() {
console.log(this.b);
}
bar()
}
foo()
猜猜答案是哪个b?正确答案是2!这就是默认绑定。绝大部分情况this指向的都是全局,但也有特殊情况,这就是我们接下来要讨论的其他绑定。
隐式绑定 --- 当函数被一个对象所拥有,再调用时,此时
this会指向该对象
var a = 3
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
obj.foo()
此时this指向的结果是2,而不是全局的3,这就是隐式绑定。让我们看看错误使用:
var a = 3
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo()
}
obj.foo
此时this指向的结果是3,而不是对象中的2,当foo不是被对象所拥有时,this就不会被对象所束缚,从而指向了全局。
隐式丢失 --- 当函数被多个对象链式调用时,
this指向引用函数的对象
var a = 3
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
var obj2 = {
a: 1,
obj: obj
}
obj2.obj.foo()
结果是指向了obj中的2,并没有被第一层的obj2所束缚,这个叫隐式丢失。
显示绑定 --- 人为干预
this,让this指向谁。使用call,apply,bind。
function foo() {
console.log(this.a);
}
var obj = {
a: 2
}
foo()
很明显,我们知道无法取到a。但我们要是将foo()换成foo.call(obj),这样我们就可以拿到a了。call的作用,强行把this的指向“掰”过去,此处是将this强行指向了obj,从而取到a。
让我们加个n,换个样子:
function foo(n) {
console.log(this.a, n);
}
var obj = {
a: 2
}
foo.call(obj, 100)
输出结果是:2 100。foo在使用call方法的时候,call又反过来调用了foo,所以可能看起来有点别扭。但这样我们就把100赋给了n,那要是再多一点呢?
function foo(n, m) {
console.log(this.a, n, m);
}
var obj = {
a: 2
}
foo.call(obj, 100, 200)
结果很明显,是:2 100 200。跟上面同理,或者使用apply:
foo.call(obj, 100, 200)
//改为
foo.apply(obj, [100, 200])
区别:apply在装参数的时候得用一个数组装起来,而不是像call一样“散装的”。再或者改成:
//1.
var bar = foo.bind(obj, 100, 200)
bar()
//2.
var bar = foo.bind(obj)
bar(100, 200)
//3.
var bar = foo.bind(obj, 100)
bar(200)
bind会按顺序来一个个赋值。
var bar = foo.bind(obj, 100, 200)
bar(300)
如果是像这样多出来的话300会被舍去。
new 绑定 --- 这个用的很多就不过多赘述。
箭头函数
箭头函数没有this这个概念,写在箭头函数中的this也是它外层函数的this。
var a = 1
// 定义一个函数:
function foo() {
console.log(this.a)
}
foo()
// 函数表达式:
var bar = function() {
console.log(this.a);
}
bar()
// 箭头函数:
var baz = () => {
console.log(this.a);
}
baz()
他们拿到的都是全局里的a,区别:上面的两个函数比如bar中的this是写在bar中的函数,而箭头函数中的this是写在全局中的。这么说可能不太明白,让我们看看例子:
var obj = {
name: "Tom",
show: function() {
var bar = function() {
console.log(this.name);
}
bar()
}
}
obj.show()
在不使用箭头函数的情况下,我们得到的结果是undefined。这时就是一层层往外指向了全局,所以拿不到obj中的Tom。
var obj = {
name: "Tom",
show: function() {
var bar = () => {
console.log(this.name);
}
bar()
}
}
obj.show()
而使用箭头函数时,this就是写在了bar的外层,在这题的情况下形成了隐式绑定,从而拿到了name,输出的结果是Tom。
Tips:箭头函数不能用作构造函数:
var Foo = () => {
}
console.log(new Foo());
像这样运行的话就会报错。
结语
这就是今天要聊的关于this的全部了。总而言之,了解学会了如何使用this,能简化我们的代码以及给我们的代码编写带来不小的便利!如果以上内容对你有帮助的话,希望能给博主一个免费的小心心♡呀~