Appearance
this 指向的方式
① 在普通函数中,this指向window
② 在构造函数中,this指向创建的对象
③ 在方法声明中,this指向调用者
④ 在定时器中, this指向window
⑤ 在事件中,this 指向事件源
//this指向window
function foo() {
console.log(this.a)
}
var a = 1foo()
//this指向obj,调用foo的对象上
const obj = {
a: 2,
foo: foo
}
obj.foo()
//this指向new这个函数上,即c
const c = new foo()
//箭头函数的this指向定义这个函数的位置,bind,apply无效,此时this指向window
function a() {
return () => {
return () => {
console.log(this)
}
}}
}
如果要判断一个运行中函数的 this 绑定, 就需要找到这个函数的直接调用位置。 找到之后 就可以顺序应用下面这四条规则来判断 this 的绑定对象。
new
调用:绑定到新创建的对象,注意:显示return
函数或对象,返回值不是新创 建的对象,而是显式返回的函数或对象。call
或者apply
( 或者bind
) 调用:严格模式下,绑定到指定的第一个参 数。非严格模式下,null
和undefined
,指向全局对象(浏览器中是 window), 其余值指向被new Object()
包装的对象。- 对象上的函数调用:绑定到那个对象。
- 普通函数调用: 在严格模式下绑定到 undefined,否则绑定到全局对象。
ES6
中的箭头函数:不会使用上文的四条标准的绑定规则, 而是根据当前的词法作用 域来决定this
, 具体来说, 箭头函数会继承外层函数,调用的this
绑定( 无论 this 绑定到什么),没有外层函数,则是绑定到全局对象(浏览器中是window
)。 这其实和ES6
之前代码中的self = this
机制一样。DOM
事件函数:一般指向绑定事件的DOM
元素,但有些情况绑定到全局对象(比如 IE6~IE8 的 attachEvent)。
改变 this 指向
1.使用 bind
var foo = {
x: 3
}
var bar = function(){
console.log(this.x);
}
bar(); // undefined
var boundFunc = bar.bind(foo); //使用bind将this绑定到window上,可以访问到foo
boundFunc(); // 3
2.let self = this
3.立即执行函数(function(j) {})(i)
bind、apply、call
在说区别之前还是先总结一下三者的相似之处:
相似之处
1、都是用来改变函数的 this 对象的指向的。
2、第一个参数都是 this 要指向的对 象。
3、都可以利用后续参数传参。
区别
1.call、apply 与 bind 都用于改变 this 绑定,但 call、apply 在改变 this 指向的同 时还会执行函数,而 bind 在改变 this 后是返回一个全新的 boundFcuntion 绑定函数, 这也是为什么上方例子中 bind 后还加了一对括号 ()的原因。
2.bind 属于硬绑定,返回的 boundFunction 的 this 指向无法再次通过 bind、apply 或 call 修改;call 与 apply 的绑定只适用当前调用,调用完就没了,下次要用还得再次绑 。
3.call 与 apply 功能完全相同,唯一不同的是 call 方法传递函数调用形参是以散列形式 ,而 apply 方法的形参是一个数组。在传参的情况下,call 的性能要高于 apply,因为 apply 在执行时还要多一步解析数组。
wx.say.bind(this) 不能立即执行,无效,必须 wx.say.bind(this)("aaa"),参数置 后
wx.say.call(this,"aaa","bbb") 立即执行,参数散列
wx.say.apply(this,["aaa","bbb"]) 立即执行,参数为数组
手写 call,apply,bind
Function.prototype.myCall =
function (ctx) {
ctx = ctx || window;
ctx.fn = this;
let args = Array.from(arguments).slice(1);
let res = ctx.fn(...args);
delete ctx.fn;
return res;
};
Function.prototype.myApply = function (ctx) {
ctx = ctx || window;
ctx.fn = this;
let args = Array.from(arguments[1]);
let res = ctx.fn(...args);
delete ctx.fn;
return res;
};
Function.prototype.myBind = function (ctx) {
let args = Array.from(arguments).slice(1);
let that = this;
return function (...oargs)
{
return that.apply(ctx, [...args, ...oargs]);
};
};