this总结
一. this是什么
- 隐藏参数
- 声明函数时附加的参数,指向调用它的对象
二. this指向
- this的指向在函数创建时是决定不了的, 在最后调用的时候才可以决定,谁调用就指向谁
三. this使用的几种情况
1. 普通函数调用(默认绑定) —> 指向window
//直接打印
console.log(this) //window
//function声明函数
function bar () {console.log(this)}
bar() //window
//function声明函数赋给变量
var bar = function () {console.log(this)}
bar() //window
//自执行函数
(function () {console.log(this)})(); //window
2. 对象函数调用(隐式绑定) —> 指向最后调用的对象
//对象方法调用
var person = {
run: function () {console.log(this)}
}
person.run() // person
window.b=2222
let obj={
a:111,
fn:function(){
alert(this.a);//111 this指向obj
alert(this.b);//undefined this指向obj,obj没有b属性
}
}
obj.fn();
2.1隐式绑定丢失问题
-
使用另一个变量给函数取别名
function foo () { console.log(this.a) }; var obj = { a: 1, foo }; var a = 2; var foo2 = obj.foo; obj.foo(); foo2();
-
把函数当做参数传递给其他函数,回调函数会丢失this指向
- 注意:还要区分是否为严格模式
- 严格模式 :会把this绑定到undefined
- 非严格模式 :会把this绑定到window
"use strict" function foo () { console.log(this.a) } function doFoo (fn) { console.log(this) fn() } var obj = { a: 1, foo } var a = 2 var obj2 = { a: 3, doFoo } obj2.doFoo(obj.foo)
3. 构造函数绑定 (new)—> 指向根据是否有实例化去判断
//不使用new指向window
function Person(name) {
console.log(this) // window
this.name = name;
}
Person('inwe')
//使用new
function Person(name) {
this.name = name
console.log(this) //people
self = this
}
var people = new Person('iwen')
console.log(self === people) //true
//这里new改变了this指向,将this由window指向Person的实例对象people
4. 箭头函数绑定 —> 指向window
- 箭头函数里面的 this 是继承外面的环境
- 向上层作用域查找
- 箭头函数的this是无法通过bind、call、apply来直接修改,但是可以通过改变作用域中this的指向来间接修改
- 字面量创建的对象,作用域是window,如果里面有箭头函数属性的话,this指向的是window
- 构造函数创建的对象,作用域是可以理解为是这个构造函数,且这个构造函数的this是指向新建的对象的,因此this指向这个对象
- 非箭头函数查找顺序:
- obj -> fn -> seTimeout -> 普通函数
- window <- 普通函数
- 箭头函数:
- obj -> fn -> seTimeout -> 箭头函数
- obj <- fn <- seTimeout <- 箭头函数
let obj={ a:222, fn:function(){ //1.不使用箭头函数 //setTimeout(function(){ console.log(this.a) }) //2.使用箭头函数 setTimeout(()=>{ console.log(this.a) }) } }; //1.不使用箭头函数的结果 //obj.fn();//undefined obj.fn();//222
5. 函数调用,call、apply传入的参数改变this指向(显式绑定)—> 根据参数决定指向
- call :
- 第一个参数决定函数体内 this 的指向,第二个参数以下是依次传入的参数;
- 在一个函数内使用call来显式绑定某个对象,这样无论怎样调用它,其内部的this总是指向这个对象
function foo1 () { console.log(this.a) } var a = 1 var obj = { a: 2 } var foo2 = function () { foo1.call(obj) } foo2() foo2.call(window)
- apply : 第一个参数决定函数体内 this 的指向,第二个参数是一个集合对象(数组或者类数组)
- bind :创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
- 注意:foo.call()和foo().call()的区别
- 前者针对函数,后者针对函数的返回值
let fn=function(a,b,c){ console.log(a,b,c); } let arr=[1,2,3]; fn.call(window,arr); fn.apply(window,arr); fn.bind(window,arr)();
6.“use strict” 严格模式
- 使用了"use strict"开启严格模式会使得"use strict"以下代码的this为undefined
四、变态题
1.显示绑定练习题
练习题原文链接: https://juejin.im/post/5e6358256fb9a07cd80f2e70#heading-15.