this
一般情况下 在全局下面 this指向的就是window(globalObject) 在node环境中指向的一个{} 因为node环境中他会从module ->加载 ->编译 ->放到一个函数里面 ->执行这个函数的apply({}) 因为这个函数调用了apply 传入了一个空对象 全局中this 就是一个空对象
所有函数被调用的时候 都会创建一个执行上下文 **在这个上下文中记录着函数的调用栈 AO对象等 并且这个AO里面 this是动态绑定的(他是在代码运行的时候已经绑定好了
他有五种的绑定规则
重点:this指向是跟他所处的位置是没有关系的,而是跟这个函数被怎么调用有关系
1. 默认绑定
**独立的函数调用 这个就是全局的window **
foo() this:window
2. 隐式绑定
它是由某一个前提调用这个方法。是有一个调用者
obj.foo() this:obj
3. 显示绑定 (在执行函数的时候 可以绑定制定this值)
提供的三种显示绑定方法
- call:
sum.call('thisVal',10,20,30)它的参数是多个 是个参数列表 - apply:
sum.apply('thisVal,[20,30,40]')他的参数是一个数组 - bind:
let newSum-sum.bind('aaa')它返回一个this为aaa的函数 foo 直接调用指向的是全局window 但是通过call,apply,bind三种方式可以指定this(这个也是跟prototype有关系) 如果传入是一个null或者undefined的话他在内部执行或进行一个忽略 他是指向window 默认绑定和显示绑定bind 起冲突了显示绑定优先级大于默认绑定
4. new绑定
我们通过一个new关键字调用一个函数时(构造器)这个时候 this是在调用这个构造器创建出来新对象 默认是一个{}
this =创造出来的对象{}
let thisObj={}
function foo (val){
console.log(this) // this=thisObj ->{}
this.name=val
return thisObj
}
let nerFoo=new foo('aa')
console.log(nerFoo.name)
- 当用new调用函数时候 会在外部先创建一个全新的对象(thisObj)
- 这个对象会被绑定到原型上(prototype)
- 这个新对象会绑定到函数调用的this上(this绑定在这个步骤完成)
- 如果函数没有返回其他对象,则会默认返回this这个新对象
5.内置函数
- 定时器
setTimeout(function(){
console.log() window 相当于独立调用这个函数 (默认绑定)
)
- 监听点击事件
const boxDiv = document.querySelector('.box')
boxDiv.onclick = function() {
console.log(this) // boxDiv这个元素
}
这个就相当于 boxDiv.onclick
- 数组的函数调用(forEach/map/filter/find)
var names = ["abc", "cba", "nba"]
names.forEach(function(item) {
console.log(item, this) // 如果传了参数 就可以执行this 如果不传参数默认就是window
}, "abc")
names.map(function(item) {
console.log(item, this)
}, "cba")
规则优先级:默认绑定是最低的 显示绑定是高于隐形绑定 new高于隐式绑定
箭头函数
- 他不会绑定this arguments属性
- 构建函数不可以作为构造函数来使用(不可以和new一起使用)
- 对象定义的函数 是没有作用域的
var obj = {
data: [],
getData: function() {
// 发送网络请求, 将结果放到上面data属性中
// 在箭头函数之前的解决方案
// var _this = this
// setTimeout(function() {
// var result = ["abc", "cba", "nba"]
// _this.data = result
// }, 2000);
// 箭头函数之后
setTimeout(() => {
var result = ["abc", "cba", "nba"]
this.data = result
}, 2000);
}
}
四种高频面试题
1.基础的调用
let names = windosPerson
let person={
names:'person',
sayNamePerson(){
console.log(this.names)
}
}
function sayName(){
let fun = person.sayNamePerson
fun() // window ;独立函数调用
person.sayNamePerson() // person ;隐式调用
(person.sayNamePerson)() // person ;隐式调用
(b=person.sayNamePerson)() // window ;赋值表达式(独立函数调用)
}
sayName()
2.嵌套箭头函数方式调用
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() // person1 : 隐式调用
person1.foo1.call(person2) // person2 (显示绑定优先级高于隐式绑定)
person2.foo2() // window :箭头函数不绑定this指向 他的上层作用域是对象 没有作用域 在上层就是全局window
person1.foo2.call(person2); // window
person1.foo3 //window :因为返回了一个函数 独立函数调用
person1.foo3.call(person2)(); // window(独立函数调用)
person1.foo3().call(person2); // person2(最终调用返回函数,这个返回的函数调用了call使用的是显示绑定)
person1.foo4()(); // person1(箭头函数不绑定this, 上层作用域this是person1)
person1.foo4.call(person2)(); // person2( 先是给foo4这个方法绑定了一个this为person2 再次调用foo4()的时候为箭头函数 它的上层作用域被显示的绑定了一个person2)
person1.foo4().call(person2); //person1 : 因为先执行了foo4 返回的结果是一个箭头函数 箭头函数是不可以绑定this的 所以当调用这个箭头函数的时候 以及寻找上层作用域 (上层找到person1)
在构造方法里面的this
var name = 'window'
function Person (name) {
this.name = name
this.foo1 = function () {
console.log(this.name)
},
this.foo2 = () => console.log(this.name),
this.foo3 = function () {
return function () {
console.log(this.name)
}
},
this.foo4 = function () {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1() // person1
person1.foo1.call(person2) // person2(显示高于隐式绑定)
person1.foo2() // person1 (上层作用域中的this是person1)
person1.foo2.call(person2) // person1 (上层作用域中的this是person1)
person1.foo3()() // window(独立函数调用)
person1.foo3.call(person2)() // window
person1.foo3().call(person2) // person2 直接给返回的函数绑定了person2
person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1
4.结合
var name = 'window'
function Person (name) {
this.name = name
this.obj = {
name: 'obj',
foo1: function () {
return function () {
console.log(this.name)
}
},
foo2: function () {
return () => {
console.log(this.name)
}
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()() // window
person1.obj.foo1.call(person2)() // window
person1.obj.foo1().call(person2) // person2
person1.obj.foo2()() // obj
person1.obj.foo2.call(person2)() // person2
person1.obj.foo2().call(person2) // obj