浅谈callapplybind
浅谈call apply bind
call方法
第一个参数是要绑定给this的值,第二部分参数要一个一个传。(当第一个参数为nll,nudefined的时候,默认指向window)
这是一个简单的例子:
//例1 var obj = { message: 'this is a people: ' } function person(name, age) { console.log(this.message + name + ' ' + age) //this is a people: xiaoming 18 } person.call(obj, 'xiaoming', 18)
了解了它的基本语法后,我们来看这样一段代码:
//例2 function a(a,b) { this.a = a; this.b = b; } function b() { this.a = 5; this.c = 3; a.call(this,1,2); } var s = new b(); console.log(s.a+","+s.b+","+s.c);输出是什么,是5,2,3 还是 1,2,3?
答案是后者,这是因为给b调用了a的call方法,使a的this指针指向了b,虽然我们在前面定义了b的a为5,但是在调用call方法之后又将b的a重写为了1。
上面两个都懂了 看一下第三个例子:
//例3 function a(){ this.show = function(){alert(this.name)} } function b(){ this.name = 'b'; } var c = new a(); var d = new b(); c.show.call(d);//b alert(d.show);//undefined //这段代码中,让c.show中的this指向了d,改变了匿名函数里面的this.name的值 //但是并没有给d写入c.show,所以第一个输出b第二个输出undefined
apply
接受两个参数,第一个参数是要绑定给this的值,所有参数都必须放在一个数组里面作为第二个参数传进去。(当第一个参数为null、undefined的时候,默认指向window。)
call 和apply是立即调用
bind
类似于call,第一个参数是this的指向,从第二个参数开始是接收的参数列表。(区别在于bind方法返回值是函数以及bind接收的参数列表。)
var obj = { name: 'xiaoming' } function person() { console.log(this.name) } var people = person.bind(obj) console.log(people) // person() {...} people() //xiaomingbind是新创建一个函数,然后把它的上下文绑定到bind()括号中的参数上,然后将它返回。所以,bind后函数不会执行,而只是返回一个改变了上下文的函数副本。(一般需要一般变量来接受它的返回值) 而原函数 printname 中的 this 并没有被改变,依旧指向全局对象 window。
bind中参数的使用:
来,我们再来看一个好玩的东西:
function fn(a, b, c) { console.log(a, b, c); } var fn1 = fn.bind(null, 'xiaoming'); //相当于已将fn1中第一个参数的值确定好了 fn('a', 'b', 'c'); // a b c fn1('a', 'b', 'c'); // dot a b //传入的实参依次向后对应一位 fn1('b', 'c'); // dot b c fn.call(null, 'xiaoming'); // dot undefined undefined
对call 来说它会严格遵照将第二个及其以后的参数作为实参传入fn,而对于bind方法 fn1的实参是在bind中已确定值的参数 基础上向后排的。
三者的使用区别:
都是用来改变函数的this对象的指向的;(第一个参数都是this要指向的对象)2.都可以利用后续参数传参; bind是返回对应函数,便于稍后调用,apply、call是立即调用;
看了这么多,你或许还回小瞧它们,难道应用它们仅仅是为了改变this指向,哈哈,当然不是了!
有何用处?
1. 将类数组转化为数组
将这个之前我们先来简单回答一下类数组和数组的关系:类数组(1)拥有length属性 (2)不具有数组所具有的方法
常见的类数组有哪些呢?
参数的参数 arguments,dom 对象列表(比如通过 document.getelementsbytags 得到的列表),jquery 对象(比如 $(“p”))
原生js中的方法: var arr = array.prototype.slice.call(类数组); 该方法等价于: var arr = [].slice.call(类数组);
刚看到设个方法的时候,自己很是疑惑,为啥这样就可以。再网上看到一篇文章博主是这样解释的,觉得很有道理:
array.prototype.slice.call(arguments);
它会将一个类数组形式的变量转化为真正的数组。为啥呢,其实书上并没有说slice还有这样的用法,也不知道是谁发明的。slice的用法可以顺便上网查一下,就能查到。但要更正一点,网上的介绍说slice有两个参数,第一个参数不能省略。然而我不知道是我理解的问题还是咋地,上面这段代码不就是典型的没传参数吗!!!arguments是传给call的那个上下文,前面讲过,不要弄混(由于arguments自己没有slice方法,这里属于借用array原型的slice方法)。而且经过测试,若果你不给slice传参数,那就等于传了个0给它,结果就是返回一个和原来数组一模一样的副本。这之后的代码就很好理解,返回一个函数,该函数把传给bind的第一个参数当做执行上下文,由于args已经是一个数组,排除第一项,将之后的部分作为第二部分参数传给apply。
2. 数组追加(当然这里可以用数组的拼接函数concat)
var arr1 = [1,2,3]; var arr2 = [4,5,6]; var total = [].push.apply(arr1, arr2);//6 // arr1 [1, 2, 3, 4, 5, 6] // arr2 [4,5,6]
在这里增加一个知识:
push 添加只能将添加项作为一个子元素,增加到母数组的后面
var arr1=[1,2,3,4]; var arr2=[5,6,7,8]; arr1.push(arr2); console.log(arr1); //(5) [1, 2, 3, 4, array(4)]
3.利用call apply做继承
function person(name,age){ // 这里的this都指向实例 this.name = name this.age = age this.sayage = function(){ console.log(this.age) } } function boy(){ person.apply(this,arguments)//将父元素所有方法在这里执行一遍就继承了 } var dcbryant = new boy('dcbryant',22)
上一篇: sudo详细介绍