我把一些 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 2015-08-20 16:55:32 +08:00
找不到对象
|
3
edire 2015-08-20 17:00:26 +08:00 1
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 1
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 不明觉厉
|