call &apply
call 可以将某个对象原本没有的方法,进行劫持,通过改变this指向让该对象也具备这种能力。
应用场景
判断js数据类型
Object.prototype.toString.call('需要判断的数据')
对象冒充式继承
function a() {
this.name = "a";
}
// a是超类;
a.prototype.play = function () {
// console.log(this.name, this);
};
function b() {
this.name = "b";
a.prototype.play.call(this); //冒充
}
b();
console.log(name);
call和apply的功能是一样的,当函数有形参传入时,apply写法上更加简洁。
第一个参数是需要改变this指向的ob。j
call 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么call的第二个参数开始一一带入所有参数。
apply 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么apply的第二个参数是这个函数的所有参数组成数组。
eg:
var obj = {
abc: function (_a, _b) {
this.a = _a;
this.b = _b;
},
};
obj.abc(1, 2);
console.log(obj);
call
实现call
Function.prototype.call = function(context = window,...args){
//将调用call的函数挂在传入的对象上,起到更改this的目的
context.fun = this;
//执行方法,并传入参数
const result = context.fun(...args);
//执行完毕删除刚创建的自定义方法,防止污染
delete context.fun;
//返回结果
return result
}
使用
var obj = {
abc: function (_a, _b) {
this.a = _a;
this.b = _b;
},
};
var obj2 = {};
obj.abc.call(obj2, 1, 2);
console.log("obj:", obj, "obj2:", obj2);
apply
var obj = {
abc: function (_a, _b) {
this.a = _a;
this.b = _b;
},
};
var obj2 = {};
obj.abc.apply(obj2, [1, 2]);
console.log("obj:", obj, "obj2:", obj2);
二者写法上有些许区别,实际作用一致。
call&apply指向
如果使用call或者apply,第一个参数是null,就意味着将函数中this重定向到window
什么时候用apply
当参数是类数组对象时
var arr=[1,3,5,6]
var max=Math.max.apply(null,arr);
因为Math.max没有this,null,传入以后并没有任何作用,目的是传参时传入的是数组
与call
、apply
的不同在于,call
、apply
调用后会立即执行,返回值依赖于调用他们的函数。而bind
,调用后会返回原函数,拥有指定的this
以及初始参数。
bind
当需要在回调函数中重新执行回调函数中的·this,就需要用bind来指向对象。bind只是创建一个新函数,不会执行。
在某些场景下,使用ES6箭头函数可以替代实现bind需求。
function fn1(fn) {
fn(3);
}
function fn2(_a) {
this.a = _a;
}
// 当需要在回调函数中重新执行回调函数中的this,就需要是用bind来指向对象
var obj = {};
// 把fn2函数中的this指向obj,并且返回这个被指向this后新的函数
fn1(fn2.bind(obj));
console.log(obj);
var fns = fn2.bind(obj);
// 这里创建了一个新的函数
console.log(fns === fn2);//false
实现Promise
class Promise1{
status="pending";
constructor(fn){
fn(this.resolve.bind(this),this.reject.bind(this));
}
resolve(result){
if(this.status!=="pending") return;
var ids=setTimeout((function(){
this.setVal("resolve",result);
clearTimeout(ids);
}).bind(this),0);
}
reject(error){
if(this.status!=="pending") return;
var ids=setTimeout((function(){
this.setVal("reject",error);
clearTimeout(ids);
}).bind(this),0);
}
then(_resolve,_reject){
this._resolve=_resolve;
this._reject=_reject;
}
catch(_reject){
this._reject=_reject;
}
setVal(_status,arg){
this.status=_status;
if(_status==="resolve" && this._resolve){
this._resolve(arg);
}else if(_status==="reject" && this._reject){
this._reject(arg);
}
}
}
ts中的私有化public、privite等可以限定属性和方法在什么地方使用,还要啥闭包呀。
This指向
普通函数
中的this ---->window
function fn(){
console.log(this);//ES5 this--->window
// ES6 严格模式 this--->undefined
}
fn();
回调函数
中的this,除了事件回调函数以外
this----->window
var arr = [1, 2, 3, 4];
arr.forEach(function () {
console.log(this); //window
});
var obj = {
a: function (fn) {
var arr = [1, 2, 3, 4];
arr.forEach(function () {
console.log(this); //window
});
setTimeout(function () {
console.log(this); //window
}, 1000);
fn();
},
b: function () {
console.log(this);
// 直接指向b函数,this---》obj
// 当把b当成回调函数带入a函数,并且执行,this--->window
},
};
obj.b();
obj.a(obj.b);
对象中的this
对象的属性如果使用this,这个this指向对象外部的this。
var a = 20;
var obj = {
a: 1,
b: this.a, //当创建到这一步时,当前这个对象没有创建完成
// 因此this指向的是当前对象外的this,对象外是window
c: function () {
// 在这里只是创建了c是一个函数,没有执行c
// console.log(this);
setTimeout(
function () {
console.log(o);
console.log(this === o); //这个this和这个setTimeout外面的this相同
}.bind(this),
2000
);
//当使用bind后,这个回调函数参数中的this和函数外this是相同的,也就是obj
},
d: () => {
console.log(this); //因为使用箭头函数,所以this被指向当前函数外的this指向
},
};
var o = obj;
obj.c(); //当执行obj.c时,obj对象是已经创建完成的,因此c函数中this就是函数外的对象自身
事件函数
事件函数,任何事件函数,this都会执行这个事件侦听的对象
document.addEventListener("click",clickHandler);
function clickHandler(e){
console.log(this);//document
}
var obj={
a:function(){
document.addEventListener("click",this.clickHandler);
},
clickHandler:function(){
console.log(this);//document
}
}
箭头函数
箭头函数的this指向声明箭头函数所在作用域外的对象(形象比喻:指向箭头函数所在的祖父级对象)。
在“use strict”严格模式下,没有直接的挂载者(或称调用者)的函数中this是指向window,这是约定俗成的。在“use strict”严格模式下,没有直接的挂载者的话,this默认为undefined。
var obj = {
b: function () {
const fun4 = () => {
console.log(this);//{b: ƒ}
};
fun4();
console.log("b", this);//{b: ƒ}
},
};
obj.b();
箭头函数在对象内定义, 因此这里的this指向则为父方法执行所在的对象。
var obj = {
fun4: () => {
console.log("fun4", this); //window
},
b: function () {
obj.fun4();
console.log("b", this); //{b: ƒ}
},
};
obj.b();