这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
this
this 的理解也是 在js 中必备的,毕竟这是js中必须要掌握的东西
全局的 this
- 这个this指向全局 windows
console.log(this, 'this')
object中的this
- 第一种是obj自己本身调用的指向obj
- 第二种是在赋值给了一个变量,这个时候调用的这个时候指向windows
- 第三种是箭头函数他会找他最近的this, 对象不构成单独的作用域(全局作用域/局部函数作用据),所以他指向了window
let obj = {
name: '我是obj的name',
fn() {
console.log(this,'this')
},
fn1: () => { console.log(this,'箭头函数的this')}
}
obj.fn()
//调用:obj.fn()
//输出:{name: "我是obj的name", fn: ƒ}
let a = obj.fn;
a();
//输出:this 指向 windows
//调用: obj.fn1()
obj.fn1();
//输出:this 指向 windows
函数内部的this
//1、普通函数
function fn() {
console.log(this, 'this')
}
//指向 window
//2、闭包函数
function fn() {
return function() {
console.log(this,'this')
}
}
let obj = {
f: fn()
}
//调用 fn()() 指向window
//调用:obj.f() 指向 obj本身
//fn() return () => {console.log(this, 'this')}
//箭头函数在上面两种情况都是指向 window
//3、构造函数
function Fn() {
console.log(this, 'this')
}
let f = new Fn();
//这个构造函数的this 指向他自己本身
改变this
有3种办法能改变this: apply、bind、call; 说一下他们的不同点:
apply
立即执行上下文(就是立即触发该函数) 参数是用数组列表接收
let obj = {
text: '掘金'
}
function fn(...args) {
console.log(this,'this', args)
return '返回值'
}
//调用fn()默认指向window;
//apply 改变this
let f = fn.apply(obj)
//1、会调用fn函数;
//2、改变this (这个时候 this指向obj)
//3、传参数是数组列表:fn.apply(obj, [1,2,3,4,5])
//4、返回值是调用的返回结果 f = '返回值'
2、call
立即执行上下文(就是立即触发该函数) 参数是用列表接收用‘逗号隔开’
let obj = {
text: '掘金'
}
function fn(...args) {
console.log(this,'this', args)
return '返回值'
}
//调用fn()默认指向window;
//apply 改变this
let f = fn.call(obj)
//1、会调用fn函数;
//2、改变this (这个时候 this指向obj)
//3、传参数是:fn.call(obj, 1,2,3,4,5)
//4、返回值是调用的返回结果 f = '返回值'
3、bind
不会立即执行上下文 ,返回函数自己本身,传参数是用列表接收用‘逗号隔开’跟call
一样
let obj = {
text: '掘金'
}
function fn(...args) {
console.log(this,'this', args)
return '返回值'
}
//调用fn()默认指向window;
//apply 改变this
let f = fn.bind(obj);
f();
//1、不会立即调用fn函数,需要手动调用下f() / fn.bind(obj)();
//2、改变this (这个时候 this指向obj)
//3、预备传参数是:fn.bind(obj, 1,2,3,4,5)
//4、直接传参就跟函数一样了fn.bind(obj)(1,2,3,4,5)
//5、返回值是fn本身
实现一个自己的call、apply
共同点: 1、立即调用 2、实现 this指向 3、实现多个参数传参 4、null 指向window
call
//实现一个自己call
//没有考虑兼容了 这样更容易理解,也更好实现
Function.prototype.myCall = function(target, ...args) {
//给obj添加一个fn函数 也就 this
const obj = target || window;
obj.fn = this;
//**这个时候调用的是obj上的fn**
let result = obj.fn(...args);
//最后删除fn
delete obj.fn
return result
}
let obj = {
name: 'call'
}
function fn(...args) {
console.log(this,'this', ...args)
}
fn.myCall(obj, 1,2,3,4,5)
fn.myCall(null, 1,2,3,4,5)
//输出验证通过
apply
function fn1(...args) {
console.log(this,'thisFn1', ...args, args)
}
let obj = {
name: 'apply'
}
Function.prototype.myApply = function(target, ...args) {
//给obj添加一个fn函数 也就 this
const obj = target || window;
if(args && args.length > 1) {
throw new Error('apply Invalid parameter')
}
obj.fn = this;
//这个时候调用的是obj上的fn
let result = obj.fn(...args[0]);
//最后删除fn
delete obj.fn
return result
}
fn1.myApply(obj, [1,2,3,4])
//验证通过 输出正确
实现一个自己的bind
//1、不是立刻调用 返回一个他自己的函数
//2、实现 this指向
//3、实现多个预参数传参 和实际参数传参合并
//4、null 指向window
Function.prototype.myBind = function(target, ...args) {
//给obj添加一个fn函数 也就 this
const obj = target || window;
let than = this;
return function(...args1) {
obj.fn = than;
//这个时候调用的是obj上的fn
let result = obj.fn(...([...args, ...args1]));
//最后删除fn
delete obj.fn
}
}
let obj = {
name: 'call'
}
function fn(...args) {
console.log(this,'this', ...args, args)
}
fn.myBind(obj, 1,2,3)(4,5,6)
//验证通过 输出正确
结束语
大家好,我是三原。我会继续保持学习总结的