关于call()方法中的this

在网上看到这样一段代码:

实现继承
function Animal(name){      
    this.name = name;      
    this.showName = function(){      
        alert(this.name);      
    }      
}      
    
function Cat(name){    
    Animal.call(this, name);    
}      
    
var cat = new Cat("Black Cat");     
cat.showName(); 

Animal.call(this) 的意思就是使用 Animal对象代替this对象,那么 Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了.

对于其中一句话不是很理解:“ Animal.call(this) 的意思就是使用 Animal对象代替this对象”。
我在犀牛书中看到,call()和apply()的第一个参数是要调用函数的母对象,它是调用上下文,函数体内通过this来获得它的引用。
在上面代码中,Animal是要调用的函数,而它没有被封装作为某个对象的属性,那么Animal的母对象不就是global对象吗?为何代码中的解释却是this指向Animal对象呢?

阅读 14k
9 个回答

好吧,我们首先来看下new做了什么:

图片描述

根据我选中部分的描述,我们知道new Cat("Black Cat")之后,Cat里面的this关键字,就指向了Cat实例本身。

然后再来看call又是怎么回事:

图片描述

仍然注意我选中的部分,thisArg(你的例子中就是Animal.call(this, name)里的this),fun(你的例子中就是Animal.call(this, name)里的Animal)。

由此我们对Animal.call(this, name)这句话,可以知道两点:

  1. 她会执行Animal方法,并传入name作为参数

  2. Animal方法里写的this会被call(this里的this(实际是Cat实例对象,上面刚讲的)替换掉

那你再想想,Animal方法里写的this.name = name;this.showName = function(){ alert(this.name); }是什么意思?其实就是cat.name = name;cat.showName = function(){ alert(cat.name); }

现在再看到cat.showName();居然能弹出来Black Cat,还会吃惊么?

这个说法是错误的

Animal.call(this) 这里的this指的是new出来的Cat对象

这样调用的作用是让Animal函数内部的this指向call()函数的第一个参数this,也就是new出来的Cat对象

换句话说,fun.call(thisArg, ...) 是让thisArg这个对象临时具有fun函数这个属性并调用执行

这会儿犀牛书不在手边,无法去核实原文。我建议你还是先看看别的资料里对 callapply 的解释,因为你所说的“母对象”并不是你自己理解的这个意思。事实上“母对象”这个翻译很奇怪,我很怀疑犀牛书的译者会写出这么个不着调的名字来,again 此时无法去核实,自己查吧,推荐去看 MDN。

1.this变量在函数执行的时候有指向,指向当前函数执行上下文-函数执行所以来的对象
2.当通过new操作符来实例化构造函数时,此时this的指向为这个实例化对象,在构造函数执行完毕后,返回这个实例对象(可以省略return this语句,或有return语句,但是返回值为基本类型时,也返回this。除了return一个对象时,就返回这个对象而不是this)
3.函数的call和apply方法可以调用执行函数并能够改变函数执行时的this指向

function Animal(name){  //Fun_Animal    
    this.name = name;      
    this.showName = function(){      
        console.log(this.name);      
    }      
}

Animal只是一个普通函数,当使用new操作符时,其才从语义上变成一个对象的构造函数。
如下代码可以调用,只是此时的this因为没有特别指定,name和showName变成了一个全局变量

    Animal('DOG');
    console.log(name);//DOG
    console.log(showName());//DOG
function Cat(name){ //Fun_Cat       
    Animal.call(this, name);    
}
Cat('cat');
console.log(name);//cat
console.log(showName());//cat

Cat也是如此,作为普通函数调用时,this也是指向全局对象,覆盖了之前Animal的执行结果
以上是不使用new操作符的情况

在使用new操作符的情况下

var cat = new Cat("Black Cat");

Cat函数作为构造函数被调用,此时的this指向以Cat为构造函数的实例对象cat_instance;
Animal.call(this, name);语句被执行,Animal是一个普通函数;
Animal函数被执行,this为Animal.call调用时传入的cat_instance,为这个对象添加name和showName属性,执行完毕后返回;
new操作符返回cat_instance给cat变量

至此,Cat构造函数通过Animal.call的调用初始化了其父类的构造函数

有这方面的笔记如下

apply and call

call方法 改变上下文环境

var files = [...]
xx = [].slice.call(files)

files截取了[]的slice方法 在slice方法内部如果有this指针项,this都指向files
xx是所截取的slice的返回值,因为参数列表中(files, ) 只有files,省略了slice的参数,没有其他所以截取了整个数组
所以xx.length = files.length
如果 xx = [].slice.call(files,0,1)
则xx的值只有files的第一个元素

apply的用法差不多 但是他还有一个特性,就是将传入的数组参数转化成参数列表

apply(this, [1,2,3,4])  ==>  apply(this, 1, 2, 3, 4)

math.max(1,2,3,4) 正确的使用方式
例如math.max([1,2,3,4]) 这样是不支持的

apply ==>  Math.max.apply(this, [1,2,3,4])  => Math.max.apply(this,1,2,3,4)  ok

我是看了好几遍你的问题,真的好绕啊。楼上说的很对,其实就先不要管什么母对象,什么对象替换对象。就只想,this就是一个指针,最开始是指向window的(当然严格模式下,是指向undefined)。函数定义并不会涉及this,只有在函数调用的时候才会。回到你的代码,cat.showName();函数执行,this的指向是发生变化的,那就看一下,是怎么变化的。
this会先指向cat(这里还有一个坑,是因为new构造函数让this指向了cat),进入cat函数后,Animal.call(this, name);这句话又改变了this的指向,又指向了Animal。这个过程很清楚了吧。其余的知识,还是看一些文章吧,有关于this的指向详细的解释。

谢谢邀请,太忙没来得及看。解决了就好

根据《高程》,new运算符干了4件事:

1.创建一个空对象;

2.将构造函数的作用域赋给新对象;

3.运行函数;

4.返回新对象;

call,apply的作用类似2,只不过传的不是构造函数,而是你指定的那个参数的作用域;
你贴的这段代码,是典型的构造函数继承;

新手上路,请多包涵

看看这样回答好不好:Animal.call("某个对象", name);
首先Animal是个函数,现在要调用这个函数,不过在传递name参数之外要额外做一件事情:
告诉Animal函数,你执行时的this是"某个对象"。
你看我这里把this替换为"某个对象",以免混淆。

你这里的Animal函数,是存在你说的那个问题的,如果直接运行这个函数,global就会生成一个name变量和一个showme函数。

如果跳脱开面向对象,从实际数据存储的角度看就会清晰很多。

推荐问题
宣传栏