call 和apply都可以执行函数
一 call和apply
call将函数中this的指向改变为这里带入的第一个参数obj
函数中如果没有this,call就没有任何意义了,和普通的执行函数概念一样
apply和call一样都是改变this的指向为第一个参数obj
function fn(){
this.a=10;
this.b=20;
}
var obj={};
//apply和call一样都是改变this的指向为第一个参数obj
fn.call(obj);
//fn.apply(obj);
console.log(obj);//{a:10,b:20}
call和apply的区别
call 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么call的第二个参数开始一一带入所有参数
apply 执行函数,并且将该函数中this指向call的第一个参数,如果该函数有参数,那么apply的第二个参数是这个函数的所有参数组成数组
function fn(_a,_b){
this.a=_a;
this.b=_b;
}
var obj={};
//fn.call(obj,3,5);
fn.apply(obj,[3,5]);
console.log(obj);//{a:3,b:20}
call将函数中this的指向改变为这里带入的第一个参数o
var obj={
abc:function(_a,_b){
this.a=_a;
this.b=_b;
}
}
//obj.abc(3,5);//obj对象的a属性变为3,b属性变为5
var o1={};
obj.abc.call(o1,3,5);//call将函数中this的指向改变为这里带入的第一个参数obj
console.log(obj,o1);// {abc()} {a:3,b:5}
如果使用call或者apply,第一个参数是null,就意味着将函数中this重定向到window
var obj={
abc:function(_a,_b){
this.a=_a;
this.b=_b;
}
}
var o1={};
obj.abc.call(null,3,5);//相当于obj.abc.call(window,3,5);
console.log(a,b);// 3,5 window上的属性
因为Math.max没有this,null,传入以后并没有任何作用,目的是传参时传入的是数组
var arr=[1,3,5,6]
var max=Math.max.apply(null,arr);
/* //重构
var Math={
max:function(){
if(arguments.length===0) return;
var max=arguments[0];
if(arguments.length===1) return max;
for(var i=1;i<arguments.length;i++){
max=max>arguments[i] ? max : arguments[i];
}
return max;
}
} */
属性和方法 动态属性,实例属性,该类的原型属性,实例化的原型链属性
动态属性 其实相对static 静态来说的
实例属性,该属性是通过new 构造函数来实例化对象以后调用的
该类的原型属性 站在类的立场上,类.prototype.属性 ES5中的方式
实例化的原型链属性 站在实例对象的的立场上,ES5中,对象中原型链上的方法和属性
<div></div>
<div></div>
<div></div>
var arr=Array.prototype.slice.call(divs);
var arr=[].slice.call(divs);//实例属性
console.log(arr);
//实现一个slice
class Array1{
constructor(){
}
slice(start,end){
// ES6中实例方法中的this就是该类实例化的对象
// console.log("aaa")
console.log(this);
start=Number(start);
end=Number(end);
if(isNaN(start)) start=0;
if(isNaN(end)) end=this.length;
if(start<0) start=this.length+start;
if(end<0) end=this.length+end;
var arr=[];
for(var i=start;i<end;i++){
arr.push(this[i]);
}
return arr;
}
}
var arr=new Array1();
//arr.slice();//slice方法中的this就是这个arr
// Array1.prototype.slice();//this是Array1.prototype 有错误的,类的原型
arr.slice.call(divs);//this是divs
//Array1.prototype.slice.call(divs);//等同于arr.slice.call(divs)
二 bind
当需要在回调函数中重新执行回调函数中的this,就需要是用bind来指向对象
function fn1(fn){
fn(3);
}
function fn2(_a){
this.a=_a;
}
var obj={};
fn1(fn2.bind(obj));//把fn2函数中的this指向obj,并且返回这个被指向this后新的函数
console.log(obj);//{a:3}
var fns=fn2.bind(obj);
console.log(fns)//这里创建了一个新的函数
console.log(fns===fn2);//false
bind的实现
function fn1(fn){
fn(3);
}
function fn2(_a){
this.a=_a;
}
var obj={};
function bind(fn,obj){
var fn1=function(){
fn.apply(obj,Array.from(arguments));
}
return fn1;
}
var fns=bind(fn2,obj);
fn1(fns);
console.log(obj);
var obj={
b:2,
a:function(){
setTimeout(function(){
console.log(this.b);//this指向window
},100)
setTimeout((function(){
console.log(this.b)//this指向bind绑定的this
}).bind(this),100) //bind绑定的this是obj
}
}
obj.a(); //2
var obj={
b:2,
a:function(){
document.addEventListener("click",this.clickHandler.bind(this));
},
clickHandler:function(e){
console.log(this.b);
document.removeEventListener("click",this.clickHandler.bind(this));//删不掉,因为this绑定会得到一个新函数
}
}
obj.a();
------------------------
var obj={
b:2,
a:function(){
this.bindHandler=this.clickHandler.bind(this)//先把绑定的函数存储起来,然后指向一个this.bindHandler,这样就可以可以删除
document.addEventListener("click",this.bindHandler);
},
clickHandler:function(e){
console.log(this.b);
document.removeEventListener("click",this.bindHandler);//删
}
}
obj.a();