call与apply浅谈

版权声明:本文为博主原创文章,未经博主允许不得转载。

 

前言

在javascript中,this是良好面向对象编程的关键,函数在各种不同的上下文中使用,一般this在调用方法时会被自动设置,但是你可以通过改变this指向来完成不同的操作,我们来谈谈改变this指向的方法

正文

call()方法

第一个用于操作this的方法是call(),它可以指定this值和参数来执行函数。call()的第一个参数指定的函数执行时this的值,其后所跟的是所有需要被传入的参数,现在来让我们看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
function sayName(parameter) {
console.log(parameter + ":" + this.name)
}
var person1 = {
name: "Lili"
};
var person2 = {
name: "Lucy"
}
var name = "Make";
sayName.call(this,"window"); //Make
sayName.call(person1,"person1Name");//Lili
sayName.call(person2,"person2Name");//Lucy

上面的code 函数接收一个parameter参数用于输出,然后该函数分别调用三次,需要注意函数调用后面不能带小括号,因为此时的函数是作为对象访问而不是执行代码,第一次传入this,输出声明在全局的Make,之后分别使用person1与person2,这时就可以看到call()方法的强大之处,我们显式的指定了this的值,这样就会覆盖javascript引擎自动的指定。如果后面需要更多的参数需要以逗号隔开。

apply()方法

apply()是第二个操作this的函数方法。它和call()的工作方式是一样的,但是它只接收两个参数:this的值和一个类数组arguments,如果是多个参数,你不需要像call()一样一个个去指定参数,只需要一个arguments参数则可以轻松搞定,除此之外,call 与 apply 的表现是一样的,来看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
function sayName(parameter) {
console.log(parameter + ":" + this.name)
}
var person1 = {
name: "Lili"
};
var person2 = {
name: "Lucy"
}
var name = "Make";
sayName.apply(this,["window"]); //Make
sayName.apply(person1,["person1Name"]);//Lili
sayName.apply(person2,["person2Name"]);//Lucy

上面的代码替换了call()结果完全相同,通常会根据已有的数据决定使用哪个方法更合适,如果你有一个数组,用apply(),如果只有一个单独变量,显然用call()更合适一些。

bind()方法

第三个方法是bind(),ECMAScript5中新加的方法,当然这个看起来就和前面两个长得不像,用法也有差异,按惯例bind()的第一个参数是要传递this的值。其他的参数需要被永久设置在新函数中,之后可以继续设置任何非永久参数。
下面让我们看两个例子,创建sayName()函数并将person1绑定为其this对象的值,然后创建sayName2()并将person2绑定为其this对象的值,person2绑定为其第一个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function sayName(parameter) {
console.log(parameter + ":" + this.name)
}
var person1 = {
name: "Lili"
};
var person2 = {
name: "Lucy"
}
var name = "Make";
var sayName1 = sayName.bind(person1);//person1绑定为其this对象的值
sayName1("person1") // person1:Lili
var sayName2 = sayName.bind(person2,"person2");//字符串为绑定的第一个参数
sayName2() // person2:Lucy 这里我们看到并没有传参数
person2.sayName = sayName1;//这里因为永久绑定,所以实际是绑定的是第一个person1
person2.sayName("person2");//person2 :Lili 这里的绑定就是sayName1绑定的person1

sayName1(),没有绑定参数,所以仍然需要传入”person1”作为参数,sayName2不仅绑定了this指向,同时也绑定了参数,所以调用时候不需要传入参数。最后将person2的sayName方法用sayName1覆盖,由于其this已经绑定,所以虽然sayName1现在是person2的方法,但它仍然输出person1的name值。

总结

函数一些叙述 可不光是call apply哦~读一下,希望对你有所帮助

javascript函数的独特之处在于它们同时也是对象,也就是说它们可以被访问,复制,覆盖,就像其它对象一样。javascript中函数和其它对象最大的区别在于它们有一个特殊的内部属性[[Call]],包含了该函数的执行指令。typeof操作符会在对象内查找这个内部属性,如果找到则返回“function”。

函数的字面形式有两种:声明和表达式。函数声明是function fnName(){},函数声明会被提升至上下文的顶部。函数表达式可被用于任何可以使用值得地方,例如赋值语句、函数参数或者另一个函数的返回值,如果函数本身内部不做返回会返回“undefined”,实例化后的构造函数返回“[object Object]”。

函数也是对象,所以存在Fnction构造函数。你可以用Function 构造函数创建新的函数,不过一般都不会这么做,因为这样看起来让人难以理解更难调试和维护。但是有时又不得不这么做,例如在函数的真实形式直到运行时才能确定的时候。
可能这句话有点难理解,我来讲个例子:
像字符串我们都知道字符不是对象,但是有没有人想过字符串明明不是对象为什么还可以调用方法,属性呢?
下面来让我们看一下内部实现的操作:

1
2
3
4
5
var name = "string";
var temp = new String(name);
var firstChar = temp.charAt(0);
temp = null;
console.log(firstChar);

这下想必各位看官应该明白了吧!

参考文献:
1.javascript面向对象摘要