<script type="text/javascript"> function Person(name,sex,age,job){ this.name = name; this.sex = sex; this.age = age; this.job = job; this.showPerson = function(){ console.log("姓名:" + this.name); console.log("性别:" + this.sex); console.log("年龄:" + this.age); console.log("工作:" + this.job); console.log(this);// Person {, sex="男", age=46, 更多...} } } var person = new Person("马云", "男", 46, "董事长"); person.showPerson(); </script>
看this指针的打印,类变成了Person,这表明function Person就是相当于在定义一个类,在javascript里function的意义实在太多,function既是函数又可以表示对象,function是函数时候还能当做构造函数,javascript的构造函数我常认为是把类和构造函数合二为一,当然在javascript语言规范里是没有类的概念,但是我这种理解可以作为构造函数和普通函数的一个区别,这样理解起来会更加容易些。
下面我贴出在《javascript高级编程》里对new操作符的解释:
new操作符会让构造函数产生如下变化:
1. 创建一个新对象;
2. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
3. 执行构造函数中的代码(为这个新对象添加属性);
4. 返回新对象
关于第二点其实很容易让人迷惑,例如前面例子里的obj和otherObj,obj.show(),里面this指向obj,我以前文章讲到一个简单识别this方式就是看方法调用前的对象是哪个this就指向哪个,其实这个过程还可以这么理解,在全局执行环境里window就是上下文对象,那么在obj里局部作用域通过obj来代表了,这个window的理解是一致的。
第四点也要着重讲下,记住构造函数被new操作,要让new正常作用最好不能在构造函数里写return,没有return的构造函数都是按上面四点执行,有了return情况就复杂了,这个知识我会在讲prototype时候讲到。
Javascript还有一种方式可以改变this指针,这就是call方法和apply方法,call和apply方法的作用相同,就是参数不同,call和apply的第一个参数都是一样的,但是后面参数不同,apply第二个参数是个数组,call从第二个参数开始后面有许多参数。Call和apply的作用是什么,这个很重要,重点描述如下:
Call和apply是改变函数的作用域(有些书里叫做改变函数的上下文)
这个说明我们参见上面new操作符第二条:
将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
Call和apply是将this指针指向方法的第一个参数。
我们看看下面的代码:
<script type="text/javascript"> var name = "sharpxiajun"; function ftn(name){ console.log(name); console.log(this.name); console.log(this); } ftn("101"); var obj = { name:"xtq" }; ftn.call(obj,"102"); /* * 结果如下所示: *101 T002.html (第 73 行) sharpxiajun T002.html (第 74 行) Window T002.html T002.html (第 75 行) 102 T002.html (第 73 行) xtq T002.html (第 74 行) Object {} * */ </script>
我们看到apply和call改变的是this的指向,这点在开发里很重要,开发里我们常常被this所迷惑,迷惑的根本原因我在上文讲到了,这里我讲讲表面的原因:
表面原因就是我们定义对象使用对象的字面表示法,字面表示法在简单的表示里我们很容易知道this指向对象本身,但是这个对象会有方法,方法的参数可能会是函数,而这个函数的定义里也可能会使用this指针,如果传入的函数没有被实例化过和被实例化过,this的指向是不同,有时我们还想在传入函数里通过this指向外部函数或者指向被定义对象本身,这些乱七八糟的情况使用交织在一起导致this变得很复杂,结果就变得糊里糊涂。
其实理清上面情况也是有迹可循的,就以定义对象里的方法里传入函数为例:
情形一:传入的参数是函数的别名,那么函数的this就是指向window;
情形二:传入的参数是被new过的构造函数,那么this就是指向实例化的对象本身;
情形三:如果我们想把被传入的函数对象里this的指针指向外部字面量定义的对象,那么我们就是用apply和call
我们可以通过代码看出我的结论,代码如下:
<script type="text/javascript"> var name = "I am window"; var obj = { name:"sharpxiajun", job:"Software", ftn01:function(obj){ obj.show(); }, ftn02:function(ftn){ ftn(); }, ftn03:function(ftn){ ftn.call(this); } }; function Person(name){ this.name = name; this.show = function(){ console.log("姓名:" + this.name); console.log(this); } } var p = new Person("Person"); obj.ftn01(p); obj.ftn02(function(){ console.log(this.name); console.log(this); }); obj.ftn03(function(){ console.log(this.name); console.log(this); }); </script>
结果如下:
最后再总结一下:
如果在javascript语言里没有通过new(包括对象字面量定义)、call和apply改变函数的this指针,函数的this指针都是指向window的。