JS中的this:
绝大多数情况下,函数的调用方式决定了this的值(运行时绑定)。this不能再执行期间被赋值,并且在函数被调用时this的值也可能会不同!
如何判断this中的值:
非严格模式-->一个对象 , 严格模式-->任意值
1.全局执行环境中,指向全局对象(非严/严格模式)
2.函数内部,取决于被调用方式
2.1直接调用的this值:
2.1.1 非严格模式: 全局对象(window)
2.1.2 严格模式: undefined
2.2 对象方法调用的this值:
2.2.1 调用者
tips:
1.'use strict' 为整个脚本开启严格模式
2.为函数开启严格模式
function func(){
'use strict'
}
3.无论上述那种情况,严格模式的开启都应置顶(注释除外) !!
如何指定this中的值:
1. 调用时指定:
1.1 call方法
依次传入参数 func.call(XXX,1,2)
1.2 applay方法
按数组传入参数 func.apply(XXX,[1,2])
2.创建时指定
2.1 bind方法
2.2 箭头函数
备注:
1、这个函数几乎与 apply() 相同,只是函数的参数以列表的形式逐个传递给 call()
,而在 apply()
中它们被组合在一个对象中,通常是一个数组——例如,func.call(this, "eat", "bananas")
与 func.apply(this, ["eat", "bananas"])
。
2、所有函数都是Function的实例对象。
手写call、apply、bind:
call:Function 实例的 call()
方法会以给定的 this
值和逐个提供的参数调用该函数。
// 1、定义myCall方法
// 3、接收剩余参数并返回结果
// ...args 表示参数不固定的剩余参数 是一个数组
Function.prototype.myCall = function(thisArg,...args){
// 2、设置this并调用原函数
// thisArg 传入的设置为this的对象
// this 原函数(原函数.myCall)
thisArg.f = this
// 调用赋值后函数,使用...args打开/展开数组
const res = thisArg.f(...args)
// 删除动态生成的属性
delete thisArg.f
console.log(args)
return res
}
// 执行代码
const person = {
name: 'ian'
}
function func(numA,numB){
console.log(this)
console.log(numA,numB)
return numA + numB
}
// 测试myCall的可复用性
function funM(numA,numB,numC){
console.log(this)
return numA*numB*numC
}
const res = func.myCall(person,2,8)
console.log('返回值1为:',res)
console.log('返回值2为:',funM.myCall(person,1,2,3))
测试手写的mycall的复用性
我们在上述代码中针对动态生成属性(方法)没有很好的处理,只是鲁莽的将其删除,而忽视可能存在f,为bug埋下隐患,为此我们将使用Symbol函数提供类似(OID)的方法来有效保护属性(方法)和删除动态生成的(方法)。
如下图可见,Symbol函数可以提供完全不同的标记。
将代码进行优化:
Function.prototype.myCall = function(thisArg,...args){
// 使用Symbol创建一个唯一的属性名
const key = Symbol()
// 将原函数赋值给thisArg对象的属性
thisArg[key] = this
// 调用赋值后函数,使用...args打开/展开数组
const res = thisArg[key](...args)
// 删除动态生成的属性
delete thisArg[key]
return res
apply:Function 实例的 apply()
方法会以给定的 this
值和作为数组(或类数组对象)提供的 arguments
调用该函数。
同理可得:
Function.prototype.myApply = function(thisArg,args){
const key = Symbol()
thisArg[key] = this
const res = thisArg[key](...args)
delete thisArg[key]
return res
}
// 执行代码
const person = {
name: 'ian'
}
function func(numA,numB){
console.log(this)
console.log(numA,numB)
return numA + numB
}
const res = func.myApply(person,[2,8])
console.log('返回值1为:',res)
bind:Function 实例的 bind()
方法创建一个新函数,当调用该新函数时,它会调用原始函数并将其 this
关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面。
// 1.定义myBind方法
Function.prototype.myBind = function(thisArg,...args){
// 返回一个函数
return (...reArgs) => {
// 调用原函数并返回结果
return this.call(thisArg,...args,...reArgs)
}
}
function func (numA,numB,numC,numD){
console.log(this)
console.log(numA,numB,numC,numD)
return numA + numB + numC + numD
}
const person = {
name: 'ian'
}
const bindFunc = func.myBind(person, 1, 2)
const res = bindFunc(3,4)
console.log(res)
小结:
通过上述代码的实现,让我对bind,apply,call方法的较为底层逻辑更加了解,在日后编写代码时可以更加恰当清楚的了解我需要什么,怎么使用。同时我对this的指向、意义、性质更为了解