箭头函数和普通函数的区别
1、箭头函数的this指向是静态的
this始终指向函数声明时所在作用域下的this的值,如果当前作用域下没有this,沿着作用域链往上寻找
var name = 'window'
const obj = {
name: 'cxk',
getName1: function() {
console.log(this.name)
},
getName2: () => {
console.log(this.name) // 定义时,当前所在作用域并没有this,沿着作用域链找到window
}
}
obj.getName1() // 'cxk'
obj.getName2() // 'window'
2、不能作为构造实例化对象
let Person = (name, age) => {
this.name = name;
this.age = age;
console.log(this)
}
Person()
let my = new Person('xie', 18); //创建不了实例化对象
console.log(my); //报错 这个this一直是指向Person的,因此创建不了
3、不能使用arguments 变量
let fn = () => {
console.log(arguments);
}
fn(1, 2, 3, 4); //报错
this指向问题
1、默认绑定
以全局作用域或者普通函数直接调用,this永远是window(注意定时器里面的this指向window)
var btn = document.getElementsByTagName('button')[0]
function fn() {
console.log(this); // Window
}
// window.fn();
fn();
// window.setTimeout(function() {
// console.log(this); // Window
// }, 1000);
//定时器前面省略了window
setTimeout(function() {
console.log(this); // Window
}, 1000);
// 这里用了隐式绑定,写在这里只是为了说明直接使用定时器其实本质就是直接全局调用
btn.onclick = function() {
//谁调用的方法,this就指向谁
console.log(this) // btn
setTimeout(function() {
console.log(this); // Window
}, 1000)
// 这里是箭头函数,this是静态是,为其函数声明时,所在作用域下的this指向
setTimeout(() => {
console.log(this) // btn
}, 1000);
}
2、隐式绑定
以方法调用的时候,谁调用的this就指向谁
案例一:
function foo() {
console.log(this) // { name: 'cxk', foo: foo(){} }
}
var obj = {
name: 'cxk',
foo: foo
}
obj.foo()
案例二:
var obj = {
name: 'cxk',
age: 16,
getAge: function () {
console.log('哥哥的年龄:', this.age) // 哥哥的年龄: undefined
}
}
var fn = obj.getAge
fn()
为什么呢?
因为this的绑定和定义的位置(编写的位置)没有关系,this的绑定和调用方式以及调用的位置有关系
this是在运行时被绑定的,不管你在哪里定义的,反正我在调用的时候是独立的,所以this是window。
案例三:
var obj1 = {
name: 'obj1',
foo: function() {
console.log(this)
}
}
var obj2 = {
name: 'obj2',
// 这里只是把obj1的函数赋值给obj2,并没有调用
bar: obj1.foo
}
// 函数是obj2调用的,所以是obj2
obj2.bar() // {name: 'obj2', bar: function() {}}
3、显式绑定
使用call和apply调用的时候,this是指定的那个对象
var obj = {
name: "obj"
}
function foo() {
console.log('函数被调用了', this)
}
foo() // Window
foo.call(obj) // {name: obj}
foo.call('call') // 'call'
foo.apply('apply') // 'apply'
var newFoo = foo.bind('aa')
newFoo() // 'aa'
4、new绑定
以构造函数调用的时候,this指向的是那个实例对象
function Fun() {
console.log(this) // this 指向的是fun实例对象
}
var fun = new Fun()
5、其他补充
5.1、显示绑定的优先级高于隐式绑定
function foo() {
console.log(this)
}
var obj = {
name: "obj",
foo: foo.bind('aaa')
}
obj.foo() // 'aaa'
5.2、new的优先级高于隐式绑定
var obj = {
name: 'obj',
foo: function() {
console.log(this)
}
}
var f = new obj.foo() // foo {}
5.3、new关键字不能和appl和call一起使用
function foo() {
console.log(this)
}
// // 特殊情况
foo.call(null) // Window
foo.call(undefined) // Window
面试题:
例子1:
var name = "222";
var a = {
name : "111",
say : function () {
console.log(this.name);
}
}
var fun = a.say;
fun(); // 空执行,没人调用 ,在全局调用的window.name 222 ,
a.say(); // a调用 111
var b = {
name : "333",
say : function (fun) {
fun();
}
}
b.say(a.say); //这里没调用fun(),空执行 222
例子2:
var name = "window"
var person = {
name: "person",
sayName: function () {
console.log(this.name)
}
}
function sayName() {
var sss = person.sayName
sss() // 相当于直接调用 'w'
person.sayName(); // 隐式调用 'p'
(person.sayName)(); // 隐式调用 'p'
(b = person.sayName)() // 直接调用 'w'
}
sayName()
例子3:
var name = "window"
var person1 = {
name: "person1",
foo1: function() {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function() {
return function() {
console.log(this.name)
}
},
foo4: function() {
return () => {
console.log(this.name)
}
},
}
var person2 = {name: 'person2'}
// 以对象的方法直接调用
person1.foo1() // 隐式调用:p1
// 通过call将this指向person2
person1.foo1.call(person2) // 显式调用: p2
// this的指向是静态的,为其声明时所在的作用域的this指向
person1.foo2() // 箭头函数:w
// this的指向是静态的,为其声明时所在的作用域的this指向
person1.foo2.call(person2) // 箭头函数: w
// 隐式调用后返回一个函数再调用,此时这个函数相当于直接调用
person1.foo3()() // 直接调用: w
// 通过call显式调用改变this指向后返回一个函数再调用,此时这个函数相当于直接调用
person1.foo3.call(person2)() // 直接调用: w
// 隐式调用后返回一个函数再调用,调用的同时通过call显式调用改变this的指向
person1.foo3().call(person2) // 显式调用: p2
// this的指向是静态的,为其声明时所在的作用域的this指向,此函数声明时上级是person1
person1.foo4()() // 箭头函数: p1
// this的指向是静态的,为其声明时所在的作用域的this指向,声明前上级已被显式改为person2
person1.foo4.call(person2)() // 箭头函数: p2
// this的指向是静态的,为其声明时所在的作用域的this指向
person1.foo4().call(person2) // 箭头函数: p1
总结:
普通函数:
- 以函数形式直接调用的时候,this永远是window
- 以方法调用的时候,谁调用的this就指向谁
- 以构造函数调用的时候,this指向的是那个实例对象
- 使用call和apply调用的时候,this是指定的那个对象
箭头函数:
- this是静态的,this始终指向函数声明时所在作用域下的 this的值,如果当前作用域下没有this,沿着作用域链往上寻找
原文链接:https://juejin.cn/post/7356041157993611276 作者:吃辣别喊我