this到底指向谁
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
多种场景下的例子
基础
//1
function a(){
var user = "tt";
console.log(this.user); //undefined
console.log(this); //Window
}
a(); // 相当于window.a
//2
var o = {
user:"tt",
fn:function(){
console.log(this.user); //tt
}
}
o.fn(); //o调用的fn, this指向o
//3 当函数中包含this,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //12
}
}
}
//this指向为“就近原则”
o.b.fn();
事件函数的this
var box=document.getElementById("box");
box.onmouseover=function(){
console.log(this);//box
}
箭头函数中的this
this指向定义的位置,而不是调用的位置
// 上例中
box.onmouseover = ()=> {console.log(this)} // this为window
//
var a=1;
var obj={
a:2,
fn1:()=>{
console.log(this.a); //this指向window
},
fn2:function(){
console.log(this.a);
}
}
obj.fn1(); //1
obj.fn2(); //2
自执行函数中的this
非严格模式,this指向window
let obj = {
name: '1',
getName: function(){
return this.name
}
}
(function(){
console.log(arguments[0]()); //this指向window
})(obj.getName)
特别注意
this永远指向的是最后调用它的对象,这里obj.getName赋值给了test,最终调用的还是window.test
let obj = {
a: '1',
getName: function() {
console.log(this.a); //this指向window,undefined
}
}
let test = obj.getName
test()
// 当遇到构造函数时,实际是new了一份对象实例赋值给了a,所以a里有user属性
function Fn(){
this.user = "追梦子";
}
var a = new Fn();
console.log(a.user);
call,apply,bind
都是修改this指向的方法
demo
let name = 'jh'
let age = 12
let obj = {
name: "hello",
age: this.age,
get: function() {
console.log(this.name + this.age)
}
}
obj.age // undefined
obj.get() // 'hello',undefined
使用apply,call,bind修改this指向
let name = 'jh'
let age = 12
let obj = {
name: "hello",
age: this.age,
get: function() {
console.log(this.name + this.age)
}
}
let kk = {
name: 'kk',
age: 11
}
obj.get.call(kk) // kk11
obj.get.apply(kk) //kk11
obj.get.bind(kk)() //kk11
bind返回了一个更改了this指向新函数
apply和call的区别
call的参数是用逗号隔开 obj.xx.call(kk,'a','b')
apply参数是用的数组 obj.xx.apply(kk,['a','b'])
有些人说call 的性能要比 apply 好一些(尤其是传递给函数的参数超过三个的时候),这个没有验证,暂时先放这吧
bind
bind实际是call的封装,返回一个不是立即执行的函数
Function.prototype.bind = function (context){
const _this = this
const args = Array.prototype.slice.call(arguments,1)
return function (){
const innerArgs = Array.prototype.slice.call(arguments)
context.call(_this,args.contact(innerArgs))
}
}
应用
- arguments 转数组
Array.prototype.splice.call(arguments)
注意
- apply或者call传入null或者undefined, this指向window
obj = {
name: '1',
test: function (){
console.log(this.name)
}
}
obj.test.call(undefined)
- 一个函数多次被bind,则后续的bind都无效 原因: bind之后相当于把this指向了第一个对象,这时再包裹就无用了。可以参考bind实现方法
test= {
name: '1',
getName: function (){
console.log(this.name)
}
}
let a = {
name: '2'
}
let b = {
name: '3'
}
test.getName.bind(a).bind(b)() //2