我们知道: var可以定义一个局部变量,当然如果var定义在最外层的话,就是全局的局部变量,也就算是全局变量了。 而this关键字定义的变量准确的说应该算是成员变量。即定义的是调用对象的成员变量。 另外在“类(构造函数)”中,我们通常也会用var定义私有属性,而this定义公共属性。 以上这些是大家都知道的,若不知道看了就大概知道的。但我今天遇到了一个疑惑,恳请社区高手指点。是这样的:
//打开浏览器控制台执行一下命令
//定义了一个全局变量
var wahaha = “娃哈哈”;//这里双引号改成英文双引号
//输出“娃哈哈”
console.log(wahaha);
//输出“娃哈哈”,我们知道这里的this指向的是window,即之前的var定义已经把wahaha变量定义成了window的成员变量
console.log(this.wahaha);
上面代码两条控制台日志语句都输出了“娃哈哈”的结果,然而如果这样
//定义一个类
function ClassA(){
//定义一个私有属性
var wahaha = “娃哈哈”;//这里双引号改成英文双引号
//输出“娃哈哈”;
console.log(wahaha);
//输出undefined
console.log(this.wahaha);
}
var a = new ClassA();
这里的输出结果就不同了 ,console.log(wahaha)顺利输出“玩哈哈”,而console.log(this.wahaha);就输出了“undefined”。其实我是觉得这个示例跟之前的那个示例的效果是有矛盾的地方的。我明白很多人利用这个特性实现私有变量跟公共变量的效果,但真的不得不说这是很矛盾的并且令人费解的。
矛盾点在于:第一个例子,var定义的全局变量会很顺利的成为window的成员变量,直接用“变量名”或者“this.变量名”都能得到结果,而第二个例子中,在构造函数中用var定义变量的话,该变量却只能在内部直接通过“变量名”获得而无法通过“this.变量名”的方式获得。
不知道我的问题描述的够不够清楚,这是今天琢磨《javascript精粹》时候想不通的一个问题。恳请高手指点
this指的不是ClassA,而是a
var是在当前作用域(scope)中声明一个变量,而this则是指向当前上下文(context)。 作用域很好理解,在函数里面,作用域就是执行var语句的那个函数,否则就是root(window或者global)。 上下文是在函数调用的时候决定的:
foo.bar() // 上下文是foo(this === foo)
foo['bar']() // 上下文是root
foo['bar'].apply(obj) // 上下文是obj
foo['bar'].call(obj) // 上下文是obj
大哥,如果你在浏览器上也写这个函数ClassA,效果是一样的啊,你在浏览器上定义的var wahaha,因为没有嵌套在函数中,所以他指向全局对象windows,而如果你在函数里面定义,this当然指向这个函数咯,看来这些要多看看咯,推荐看看犀牛。
非常感谢您的回复,但请看清楚我的问题
这貌似跟我的疑惑没有关系啊?
@xlqstar 没有关系?哈哈,看看作用域和函数吧,再看看函数作用域.
不能说乱指吧,反正规律不好找,我就把我遇到的这个特殊情况背下来得了,理解不了
@jiyinyiyong js表示无视了
不会别的,不懂专业术语.不过听说js和别的高级面向对象的好像有些不同.
`var wahaha = ‘爽歪歪’ ; function ClassA(){
//定义一个私有属性 var wahaha = “娃哈哈”;//这里双引号改成英文双引号 this.wahaha = wahaha ;
//输出undefined console.log(wahaha +"\n"+ this.wahaha +"\n"+ ClassA.wahaha ); } ClassA.wahaha = “wahaha” ;
var a = new ClassA(); console.log("\n" + wahaha +"\n"+ this.wahaha +"\n"+ ClassA.wahaha );`
楼主的意思是在window对象里用var声明变量,该变量可以顺利成为window的公开属性,而在自定义的class里确不能,
同疑惑,哈哈,不过javascript作为弱语言,很多特性都跟它的解释器有很大的关系,偶尔出点幺儿子也是很正常的
o(∩_∩)o 哈哈 终于有人明白我的帖子具体是在说什么的了~~ 对的,就是您说的这个疑惑~~我只能暂且把这个情况作为一个特例,记着了……
foo.bar() // 上下文是foo(this === foo)
foo['bar']() // 上下文是root
上面两行代码我经过测试,您说的这个情况不成立啊!不知道您的测试代码是怎样的?着两行的测试结果应该是一样的才对,无论什么情况下。
摘自《深入浅出CoffeeScript》:
回忆一下,下面对CoffeeScript中上下文的规则做了个总结,前面的的规则优先于后面的规则: (1). 当在一个函数调用之前有new关键字,则上下文为新建的对象; (2). 当一个函数使用call或者apply调用时,给定的第一个参数即为上下文; (3). 否则,如果一个函数作为一个对象的属性(obj.func)或者obj[‘func’])来调用时,它就把该对象作为上下文来运行; (4). 如果与上述几条都不符的话,则函数将在全局上下文中运行。
继续来分析你的问题:
这是一个作用域和上下文的问题。在JavaScript中,this
指向当前的上下文,而var
定义的变量值在当前作用域中有效。
JavaScript有两种作用域,全局作用域和局部作用域。局部作用域就是在一个函数里。
var
关键字使用来在当前作用于中创建局部变量的,而在浏览器中的JavaScript全局作用域中使用var
语句时,会把申明的变量挂在window
上,而全局作用域中的this
上下文恰好指向的又是window
,因此在全局作用域中var
申明的变量和window
上挂的变量,即this
可访问的变量有间接的联系,但没有直接联系,更不是一样的。
考虑new
一个函数,根据上面的(1)知道,执行构造函数时,上下文this
为新建的对象(该对象的原型链__proto__
指向了该函数的prototype
,这就是原型继承,顺便提一下,与本问题无关),而作用域确实局部的,与this
完全不同,所以自然没有什么联系,双方的赋值不会互相影响。
形象点说:
作用域就是一个执行过程,这个执行过程在JavaScript中就是一个函数,这个执行过程是如何和外界互相沟通的呢?
1.参数和返回值
2.上一级的作用域
3.this
,即上下文
在作用域中创建的变量,函数执行外就被清除了。
@xlqstar 是,不好意思,我错了,应该是这样:
foo.bar() // 上下文是foo(this === foo)
var bar = foo.bar
bar() // 上下文是root
bar.apply(obj) // 上下文是obj
bar.call(obj) // 上下文是obj
@xlqstar 可是你的例子本身就不是同一个,你前端用了A例子,后端用了B例子,A!==B,没有可比性,所以出不来你想要的结果么。
@island205 非常感谢您的剖析,您提到的"作用域就是一个执行过程"这句话很有道理,但有些地方具体一推敲又会又很多疑惑,继续刨根问底下去代价太大,这应该跟js的运行机制有关系,我还是宁愿把此作为特殊情况记住得了。 另外我at一下 @BYVoid 看看他有什么好的解释不
at错了 重新at下 @byvoid
@xlqstar 这些东西,多接触接触就会立即的。
用this定义的是成员变量,用var定义的是局部变量,
function ClassA(){ var wahaha = ‘娃哈哈’; console.log(wahaha); console.log(this.wahaha); console.log(this); }
var a = new ClassA(); ClassA();
试试上面的语句,有助于理解。 1楼回复的对。。