1
hitsmaxft 2014-06-01 09:47:27 +08:00 1
call 和 apply 只是传参方式不同, 作用都一样的, 执行一个函数,并替换作用域里的 this 指向的实例
这段代码里面带 this 的 函数, 可以当成构造器, 那么用了 apply 相当于把当前的 this 重新初始化了一遍, 所以属性修改了. 你的不理解跟 apply 的工作原理没啥关系, 是不熟悉 javascript 的构造器写法导致的.. |
2
ety001 OP @hitsmaxft 貌似你没有看懂我要表达的问题。我的问题其实是质疑用“替换”这个词来表述,因为我写的那个代码的执行结果并不是“替换”,而是“补充”,如果是“替换”的话,第20行打印出来的this应该是Print的内容才对,而实际打印的内容是Person,Print,Student2的合并后的内容。
因为看到很多人都是用“替换”这个词,所以我在想是不是我哪个地方没有理解正确。 就像你所说的,使用apply相当于是把当前的this重新初始化了一遍,问题就出在这个重新初始化,到底应该是表述为用一个类去替换当前类,还是用一个类去补充当前类。实际的操作来看,这是一个补充的过程。 |
3
SoloCompany 2014-06-01 11:09:08 +08:00 1
把 this 看成一个显示参数而不是隐式参数,那么 call 和 apply 的左右就容易理解了,这两个方法用途是完全一样的,使用哪个取决于你的参数是怎么取得,call 和你直接调用一个方法完全一样,只是第一个参数变成了 this,其余参数位置自动加一,apply 就完全不同,所有参数作为数组放到第二个参数中传递
|
4
ispinfx 2014-06-01 11:42:59 +08:00 1
输出的东西有你说合并的东西没啥问题啊,我觉得是LZ没弄清楚被替换的是当前对象这里.
|
5
Mutoo 2014-06-01 11:45:50 +08:00 1
> [我的理解]
> Obj.apply(thisObj,[]) 很明显,你这里误解了一个东西, Obj. 应该是 Function. 才对 Obj是构造函数,或者一般化为普通函数。 函数执行时有上下文(context),js通过这个上下文来查找变量。 function.apply(thisObj, [arguments..]) 的意思是 以 thisObj 作为 this 的引用变量,执行 function(arguments...) |
6
ispinfx 2014-06-01 11:51:05 +08:00
|
7
serenader 2014-06-01 12:10:45 +08:00 1
在执行 var s = new Student2('Jim',22,'Harvard',2); 这个表达式时其实 Student2 函数内部的 this 指向的都是新实例,也就是 s 。
而所谓的替换过程其实是发生在调用 apply 或者 call 的这个函数内部的。在你这个例子中, var Student2 = function(name,age,school,grade){ Person.apply(this,arguments); Print.apply(this,arguments); console.log(this); this.school = school; this.grade = grade; } Person.apply(this,arguments) 的意思是,调用 Person 这个函数,然后将 Person 内部的 this 替换为(或者说切换为)apply 方法传递进去的第一个参数,也就是 this 。 不知道你理解不。 “Obj.apply(thisObj,[]) 如果把apply和call分别翻译成“应用”和“调用”,那么我的理解是,thisObj应用(调用)Obj,并把[]作为Obj的传入参数,而不是以[]作为Obj的参数并替换thisObj。” 理解有些不当。应该是, 调用 Obj 这个函数,并且将 Obj 的上下文切换为传递进 apply 方法的第一个参数。然后 [] 是作为 Obj 的参数传递的。而这整个过程中,Student2 的 this 并没有变。当构造新实例时是始终指向新实例的。 所以你给出的例子就可以很好的理解了。 附上 jsfiddle 。我只是写了一些注释。 http://jsfiddle.net/Jx8r7/ 另外楼主可以看看这两个链接,有帮助你理解 this 和 call/apply 阮一峰:Javascript的this用法 http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html 郭培:Javascript中call的使用 http://hszy00232.blog.163.com/blog/static/43022753201131835653841/ |
8
emric 2014-06-01 12:39:20 +08:00 1
https://gist.github.com/unmric/288312be28eefdb3e716
你多想了, 试试这样理解? |
9
lijsh 2014-06-01 12:44:39 +08:00 1
楼主,console的一行是不会有school和grade属性输出的,因为还没到这两个属性的赋值部分。
替换这个说法是没错的,对于apply和call,第一个参数就是代表上下文的替换(当然切换更好)。 这里当以new调用Student2的时候,Student2里的this都会指向实例后的对象,这里就是s;既然内部的this都是指向同一个引用,两个apply所谓的替换看起来更像补充作用。 |
10
lijsh 2014-06-01 12:47:34 +08:00
楼主的第二条补充有点不严谨,应该是在Student2里把Person的上下文切换到Student2中的this。
|
11
zzNucker 2014-06-01 12:53:24 +08:00
我觉得lz的补充说明他还是不懂。。。。。
|
12
andy12530 2014-06-01 13:04:26 +08:00 1
我是不能理解为毛20行不能 打印出name,age,school和grade,都说是替换了,又不是把Student2里面的this删掉,后面又对this添加了school等属性。
顺便说一句,浏览器里面的console.log是异步的。 |
13
andy12530 2014-06-01 13:13:15 +08:00
『其实apply就是把你想要进行继承操作的构造方法(比如我例子中的Student2)的上下文交给你想要集成的构造方法』
LZ 你还是没理解。 apply和call方法的功能,只是 "调用一个函数", 把这个 函数里面的 this 变成你传递的第一个参数。 例子:Array.prototype.slice.call(ListCollection),本来slice这个方法只能在array上调用,通过call方法,我们可以slice方法在非数组元素上。 |
14
ety001 OP @lijsh
以18行的代码为例,就是把当前Student2的this传递给了Person,apply会把Person作为实施目标,用传入的Student2的this替换原有的this,所谓的替换,应该就是这一步,之前理解不了,就是因为把这个替换的方向搞反了,一直认为是Person的this替换了Student2的this。 说白了,就是把Student2的this告诉了Person,让Person可以直接操作这个this,通过这个方式让Student2拥有Person的一些属性。 @andy12530 浏览器里面的console.log是异步的,这个之前还真是不清楚。不过上午做这个试验的时候,看到这个结果,有想到这个console.log可能会是异步。另外我觉得你说的“apply和call方法的功能,只是 "调用一个函数", 把这个 函数里面的 this 变成你传递的第一个参数”跟我理解的意思是一致的。 |
15
jakwings 2014-06-01 16:17:23 +08:00
相信大家已经解释清楚了。我补一个相关的细节问题:经过 .bind(this) 产生的新函数,无法再替换 this,即是说:
function a() { console.log(this); } a.call({x: 1}); //=> {x: 1} b = a.bind({y: 2}); b.call({x: 1}); //=> {y: 2} |