我把一些 DOM 方法赋给变量,以供方便使用,但是遇到了错误。
var gTag = document.getElementsByTagName; // undefined gTag // getElementsByTagName () gTag ("p") // TypeError: 'getElementsByTagName' called on an object that does not implement interface Document.
刚接触 JS 没多久,非常不理解,为什么把这个方法赋给变量,不用括号输入变量名就是直接调用了。
然后我了解了下 call 和 apply 方法,原来 JS 下有这种好用的机制,一个新对象未定义一个方法,可直接调用旧对象的方法,只需要把新对象作为 this 传给旧对象的方法。
function Old (){} Old.prototype = { name: "old name", run: function (){ console.log ("Name is: " + this.name ); } } var o = new Old; var New = { name: "new name" }; o.run (New ); // Name is new name var run = o.run; run.call (o ); // name is old name
但是我非常不理解为什么把实例的方法赋值给一个变量后会丢失 this 指针。
这里无意挑起语言的纷争!!
然后我想起了 Python 的类:
class A: def run (self ): return "running" a = A () run = a.run run () A.run () """Traceback (most recent call last ): File "<stdin>", line 1, in <module> TypeError: unbound method run () must be called with A instance as first argument (got nothing instead )""" A.run (a )
好像明白了些什么,但是又好像模糊!
JS 里面把实例方法赋值给变量,以变量再调用,但是 this 会丢失。就好像如 Python 中的 A.run
未实例化直接使用,也会报错。 JS 在 nodejs 环境下虽然未报错,但是输出的是 Name is undefined 也就是说找不到 this.name ,当成一个普通函数运行了。
我的理解是否有误?
现在还是不太明白为什么对实例方法赋值操作 var a = object.method
会丢失 this 。
1 edire 2015-08-20 16:54:09 +08:00 被你说晕了。真心被你说晕了。我先回答你最后一个问题 |
![]() | 2 void1900 div class="badges"> 2015-08-20 16:55:32 +08:00 找不到对象 |
3 edire 2015-08-20 17:00:26 +08:00 ![]() var a = object.method 会丢失 this 。 不是会丢失 this 。是这样的你看这个 var object = { name: 'username', method: function () { console.log (this.name ); } }; 我如果执行 object.method (); 这样的话 他就会输出 username 如果我先赋值给 a; var a = object.method 那么,其实等于 var a = function () { this.name; } 当前的 this 指向的是 window ,也就是 window.name |
![]() | 4 cc7756789 OP |
![]() | 6 FrankFang128 2015-08-20 17:03:53 +08:00 看在用 Java 的角度理解 Javascript 我就明白了你为什么疑惑了。 你这样是想不通的。 请忘掉传统的 OOP ,进入 prototype 的世界。 |
![]() | 7 FrankFang128 2015-08-20 17:04:54 +08:00 ![]() this 不会丢失, this 永远指向 context , this 不会指向「当前对象」。 |
![]() | 8 Arrowing 2015-08-20 17:05:03 +08:00 var gTag = document.getElementsByTagName; 这一句只是将 getElementsByTagName 这个方法引用赋值给 gTag 而 js 里是方法执行时确定上下文对象的,当你执行这个方法时,会查找上下文对象,而这里明显缺乏一个上下文对象 错误提示是 getElementsByTagName 的上下文对象必须是 document 或集成 document 的 你可以这样: var gTag = function (tagName ){ return document.getElementsByTagName (tagName ); }; gTag ('p'); 或者这样: var gTag = document.getElementsByTagName.bind (document ); gTag ('p'); |
9 sudoz 2015-08-20 17:07:49 +08:00 @FrankFang128 是这么回事 |
![]() | 10 q84629462 2015-08-20 17:08:24 +08:00 [var a = object.method 会丢失 this ] 并不是丢失了 this : var a = {a:function (){console.log (this );}}; var b = a.a; a.a (); b (); this 一直都在,只是这个 function 的运行环境改变了 |
11 edire 2015-08-20 17:08:42 +08:00 然后 call o.run.call (New ) 实现了什么 实现了一个 让 run 这个方法运行的时候作用域 this 指向了 New ,所以 那个地方的 this.name 也就是 "new name" |
![]() | 12 WXYOO1 2015-08-20 18:06:59 +08:00 问题一:像 @Arrowing 所说的, Js 自带的方法要考虑上下文, document.getElementsByTagName 必须绑在全局上。 另外扩展 Js 本身的一些方法一般是重新定义一下:比如像一些 ie 兼容的扩展方法等 var gTag = function (tagName ){ return document.getElementsByTagName (tagName ); }; gTag ('p'); 问题二:两个关注点: 1.prototype 和 call\apply function Old (){} Old.prototype = { name: "old name", run: function (){ console.log ("Name is: " + this.name ); } } var o = new Old; var New = { name: "new name" }; o.run (New ); // Name is (old old old )/3 遍 name //o.run 并没有接受参数的地方,你应该要写成 o.run.call (New );吧? //1. o.run (New ); 打印 old name 的原因是 o.run o 从类 Old 定义而来,而 Old 的 prototype.name = “ old name ”; //2. 若你本意是 o.run.call (New ) 则打印 Name is new name 此处指针会指向 New 对象。 |
![]() | 13 latelx 2015-08-20 18:51:12 +08:00 你可以用 bind 把上下文绑定在方法上啊 var run = o.run.bind (o ) run (); |
14 YuJianrong 2015-08-20 19:17:18 +08:00 via iPhone 对 JS 语法有任何疑问去看语言 spec 是最简单的办法, es6 有点厚就算了,大部分特性去看薄薄的 es3 标志就好了。 |
15 Rube 2015-08-21 11:09:02 +08:00 js 作用域链 |
16 bramblex 2015-08-21 14:56:08 +08:00 OwO 不明觉厉 |