背景介绍
call 和 apply 都是为了改变某个函数运行时的 context 即上下文而存在的
换句话说, 就是为了改变函数体内部 this 的指向因为 JavaScript 的函数存在定义时上下文和运行时上下文以及上下文是可以改变的这样的概念
知识剖析
apply
方法能劫持另外一个对象的方法, 继承另外一个对象的属性. Function.apply(obj,args) 方法能接收两个参数
obj: 这个对象将代替 Function 类里 this 对象
args: 这个是数组, 它将作为参数传给 Function(args-->arguments)
call
和 apply 的意思一样, 只不过是参数列表不一样
Function.call(obj,[param1[,param2[,[,paramN] ] ] ] )
obj: 这个对象将代替 Function 类里 this 对象
params: 这个是一个参数列表
常见问题
如何使用 call 和 apply?
解决方案
call 和 apply 的作用基本类似, 都是去执行 function 并将这个 function 的 context 替换成第一个参数带入两者的不同是 call 必须将 function 的参数一一带入, 接受的是连续参数而 apply 接受的是数组参数 只要在第二个参数带入一个数列
- //j k 形參
- function add(j, k) {
- return j + k;
- }
- function sub(j, k) {
- return j - k;
- }
- // 5 3 實參
- add(5, 3); //8
- add.call(sub, 5, 3); //8
- add.apply(sub, [5, 3]); //8
- sub(5, 3); //2
- sub.call(add, 5, 3); //2
- sub.apply(add, [5, 3]); //2
- // 通过 call 和 apply 实现对象继承
- var Parent = function() {
- this.name = "yjc";
- this.age = 22;
- };
- var child = {};
- console.log(child); //Object {} , 空对象
- Parent.call(child);
- console.log(child); //Object {name: "yjc", age: 22}
- //call 方法 1
- window.color = "red";
- document.color = "yellow";
- var s1 = {
- color: "blue"
- };
- function changeColor() {
- console.log(this.color);
- }
- //2
- changeColor.call(); //red (默认传递参数)
- changeColor.call(window); //red
- changeColor.call(document); //yellow
- changeColor.call(this); //red
- changeColor.call(s1); //blue
- var Pet = {
- words: "...",
- speak: function(say) {
- console.log(say + "" + this.words);
- }
- };
- Pet.speak("Speak"); // 结果: Speak...
- var Dog = {
- words: "Wang"
- };
- // 将 this 的指向改变成了 Dog
- Pet.speak.call(Dog, "Speak"); // 结果: SpeakWang
- //apply 方法 1
- window.number = "one";
- document.number = "two";
- var s1 = {
- number: "three"
- };
- function changeColor() {
- console.log(this.number);
- }
- changeColor.apply(); //one (默认传参)
- changeColor.apply(window); //one
- changeColor.apply(document); //two
- changeColor.apply(this); //one
- changeColor.apply(s1); //three
- // 方法 2
- function Pet(words) {
- this.words = words;
- this.speak = function() {
- console.log(this.words);
- };
- }
- function Dog(words) {
- //Pet.call(this, words); // 结果: Wang
- Pet.apply(this, arguments); // 结果: Wang
- }
- var dog = new Dog("Wang");
- dog.speak();
实例
- // call 方法可以用来代替另一个对象调用一个方法,
- // call 方法可以将一个函数的对象上下文从初始的上下文改变为 thisObj 指定的新对象,
- // 如果没有提供 thisObj 参数, 那么 Global 对象被用于 thisObj.
- //1:
- function add(c, d) {
- return this.a + this.b + c + d;
- }
- var s = { a: 1, b: 2 };
- console.log(add.call(s, 3, 4)); // 1+2+3+4 = 10
- console.log(add.apply(s, [5, 6])); // 1+2+5+6 = 14
- //2:
- window.firstName = "Cynthia";
- window.lastName = "_xie";
- var myObject = { firstName: "my", lastName: "Object" };
- function getName() {
- console.log(this.firstName + this.lastName);
- }
- function getMessage(sex, age) {
- console.log(
- this.firstName + this.lastName + "性别:" + sex + "age:" + age
- );
- }
- getName.call(window); // Cynthia_xie
- getName.call(myObject); // myObject
- getName.apply(window); // Cynthia_xie
- getName.apply(myObject); // myObject
- getMessage.call(window, "女", 21); //Cynthia_xie 性别: 女 age: 21
- getMessage.apply(window, ["女", 21]); // Cynthia_xie 性别: 女 age: 21
- getMessage.call(myObject, "未知", 22); //myObject 性别: 未知 age: 22
- getMessage.apply(myObject, ["未知", 22]); // myObject 性别: 未知 age: 22
拓展
call() 和 apply() 两种方法的区别?
相同点: 两个方法产生的作用是完全一样的
不同点: 方法传递的参数不同
call() 接受的是一个参数列表, 而 apply() 接受一个参数数组
- func.call(this, arg1, arg2);
- func.apply(this, [arg1, arg2]);
其中 this 是你想指定的上下文, 他可以是任何一个 JavaScript 对象 (JavaScript 中一切皆对象),
call 需要把参数按顺序传递进去, 而 apply 则是把参数放在数组里
因此要说适用条件的话, 当你的参数是明确知道数量时用 call
而不确定的时候用 apply, 然后把参数 push 进数组传递进去
参考文档
參考
Q&A
Q1: 是 call 还是 apply 能改变 this 的指向?
A1: 两个都能改, 就是传参数方式不一样呀, apply 传数组, call 传字符串
Q2:apply 的应用场景呢??
A2: 首先从网上查到关于 apply 和 call 的定义, 然后用示例来解释这两个方法的意思和如何去用.
apply: 方法能劫持另外一个对象的方法, 继承另外一个对象的属性. Function.apply(obj,args) 方法能接收两个参数 obj: 这个对象将代替 Function 类里 this 对象
args: 这个是数组, 它将作为参数传给 Function(args-->arguments), call: 和 apply 的意思一样, 只不过是参数列表不一样.
Function.call(obj,[param1[,param2[,[,paramN]]]])
obj: 这个对象将代替 Function 类里 this 对象
params: 这个是一个参数列表
apply 示例
- /* 定义一个人类 */
- function Person(name,age) {
- this.name=name; this.age=age;
- }
- /* 定义一个学生类 */
- functionStudent(name,age,grade) {
- Person.apply(this,arguments); this.grade=grade;
- }
- // 创建一个学生类
- var student=new Student("qian",21,"一年级");
- // 测试
- alert("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);
- // 大家可以看到测试结果 name:qian age:21 grade: 一年级
- // 学生类里面我没有给 name 和 age 属性赋值啊, 为什么又存在这两个属性的值呢, 这个就是 apply 的神奇之处.
分析: Person.apply(this,arguments);
this: 在创建对象在这个时候代表的是 student
arguments: 是一个数组, 也就是 [qian,21, 一年级];
也就是通俗一点讲就是: 用 student 去执行 Person 这个类里面的内容, 在 Person 这个类里面存在 this.name 等之类的语句, 这样就将属性创建到了 student 对象里面
Q3:call 的应用场景呢??
A3: 在给对象参数的情况下, 如果参数的形式是数组的时候, 比如 apply 示例里面传递了参数 arguments, 这个参数是数组类型, 并且在调用 Person 的时候参数的列表是对应一致的 (也就是 Person 和 Student 的参数列表前两位是一致的) 就可以采用 apply , 如果我的 Person 的参数列表是这样的 (age,name), 而 Student 的参数列表是 (name,age,grade), 这样就可以用 call 来实现了, 也就是直接指定参数列表对应值的位置 (Person.call(this,age,name,grade));
来源: http://www.jianshu.com/p/88bc6e45d67c