This
JavaScript 得this指向是动态得,只有当你调用得时候才确定this得指向,这有时候很苦恼。
this
一句话:this指向调用它所处环境得上下文空间,也是指向最近调用它得对象。
在事件中,this 表示接收事件的 DOM 对象。
如下:调用obj.fnc()时,fnc函数所处得环境为obj对象,this就指向obj,函数执行打印0,执行fnc()时,由于fnc = obj.fnc操作,此时fnc变量指向函数本身,调用函数this就指向此时得环境即window,指向函数打印1。
js
var a = 1
const obj = {
a: 0,
fnc: function () {
console.log(this.a)
}
}
const fnc = obj.fnc
obj.fnc() //0
fnc() //1又一个例子。这里的this指向obj.b。
js
const obj = {
a: 0,
b: {
a: 1,
fnc() {
console.log(this.a) //1
}
}
}
obj.b.fnc()改变 this
改变this指向有new,即构造函数,call,apply,和bind,以及箭头函数。
优先级:new操作符>call方法等>箭头函数>其他
new
new操作会把this指向绑定到生成的对象。
js
function Fnc() {
this.a = 0
}
const f = new Fnc()
console.log(f.a) //0new操作做了什么?
- 生成一个新对象
- 链接原型
- 绑定 this
- 放回新对象
注意最后是返回一个对象。这个对象是默认返回的,如果你主动return一个对象,那么this指向你返回的那个对象。
js
function Fnc() {
this.a = 0
return {
a: 1
}
}
const f = new Fnc()
console.log(f.a) //1提示
手动放回一个对象会导致原型指向改变。
js
Fnc.prototype.b = 10
console.log(f.b) //undefinedcall 和 apply
call和apply均可修改this,不同的是参数传递方式。可结合 es6rest参数使用。
js
const f = {
a: 1,
fnc: function (...res) {
console.log(this.a + ',' + res)
}
}
const obj = {
a: 0
}
f.fnc.call(obj, 1, 2, 3) //0,1,2,3
f.fnc.apply(obj, [1, 2, 3]) //0,1,2,3bind
bind的使用方法和call一样,不同的是它放回一个函数,
js
const f = {
a: 1,
fnc: function (...res) {
console.log(this.a + ',' + res)
}
}
const obj = {
a: 0
}
const F = f.fnc.bind(obj, 1, 2, 3)
F() //0,1,2,3箭头函数
箭头函数的this会指向原本指向的环境得上一层环境。
js
var a = 0
const f = {
a: 1,
fnc: (...res) => {
console.log(this) //window
console.log(this.a + ',' + res) //0,1,2,3
}
}
f.fnc([1, 2, 3])对于对象,无论嵌套多深都是指向最外层对象。
js
var a = -1
const obj = {
a: 0,
b: {
a: 1,
fnc: () => {
return this.a
}
}
}
obj.b.fnc() //-1
const test = obj.b.fnc
test() //-1手写 call 等
call和apply一类。bind一类。
call 和 apply
call使用rest进行参数收集,这里只是非严格模式下的写法模拟。通过调用对象得方法来改变函数得this指向。
js
Function.prototype.myCall = function (context = window, ...res) {
//参数传入模拟
if (context === null) context = window
else if (typeof context === 'number') context = new Number(context)
else if (typeof context === 'string') context = new String(context)
else if (typeof context === 'boolean') context = new Boolean(context)
const symbol = Symbol('temporary')
context[symbol] = this
const result = context[symbol](...res)
delete context[symbol]
return result
}使用:
js
const demo = {
a: 1,
fnc(...res) {
console.log(this) //瑕疵 {a:0,Symbol(temporary): f}
console.log(this.a + ',' + res) // 0,1,2
return res
}
}
const obj = {
a: 0
}
var a = 100
const p = demo.fnc.myCall(obj, 1, 2)
console.log(...p) //1 2apply使用数组传参,就不使用rest收集参数。
js
Function.prototype.myApply = function (context = window, res) {
//代码一样
}
const p = demo.fnc.myApply(obj, [1, 2])bind
bind放回一个函数,这个函数可以被调用,也可以作为构造函数使用。
js
Function.prototype.myBind = function (context, ...res) {
const fnc = this
return function F(...args) {
if (this instanceof F) {
return new fnc(...res, ...args)
}
return fnc.call(context, ...res, ...args)
}
}使用:
js
const demo = {
a: 1,
fnc(...res) {
console.log(this) //{a:0}
console.log(this.a + ',' + res) // 0,1,2,3
return res
}
}
const obj = {
a: 0
}
var a = 100
const p = demo.fnc.myBind(obj, 1, 2)(3)
console.log(p) //[1,2,3]