4) this、new、call和apply的相关问题
讲解this指针的原理是个很复杂的问题,如果我们从javascript里this的实现机制来说明this,很多朋友可能会越来越糊涂,因此本篇打算换一个思路从应用的角度来讲解this指针,从这个角度理解this指针更加有现实意义。
下面我们看看在java语言里是如何使用this指针的,代码如下:
public class Person { private String name; private String sex; private int age; private String job; public Person(String name, String sex, int age, String job) { super(); this.name = name; this.sex = sex; this.age = age; this.job = job; } private void showPerson(){ System.out.println("姓名:" + this.name); System.out.println("性别:" + this.sex); System.out.println("年龄:" + this.age); System.out.println("工作:" + this.job); } public void printInfo(){ this.showPerson(); } main(String[] args) { Person person = new Person("马云", "男", 46, "董事长"); person.printInfo(); } } //姓名:马云 //性别:男 //年龄:46 //工作:董事长
上面的代码执行后没有任何问题,下面我修改下这个代码,加一个静态的方法,静态方法里使用this指针调用类里的属性,如下图所示:
我们发现IDE会报出语法错误“Cannot use this in a static context”,this指针在java语言里是不能使用在静态的上下文里的。
在面向对象编程里有两个重要的概念:一个是类,一个是实例化的对象,类是一个抽象的概念,用个形象的比喻表述的话,类就像一个模具,而实例化对象就是通过这个模具制造出来的产品,实例化对象才是我们需要的实实在在的东西,类和实例化对象有着很密切的关系,但是在使用上类的功能是绝对不能取代实例化对象,就像模具和模具制造的产品的关系,二者的用途是不相同的。
有上面代码我们可以看到,this指针在java语言里只能在实例化对象里使用,this指针等于这个被实例化好的对象,而this后面加上点操作符,点操作符后面的东西就是this所拥有的东西,例如:姓名,工作,手,脚等等。
其实javascript里的this指针逻辑上的概念也是实例化对象,这一点和java语言里的this指针是一致的,但是javascript里的this指针却比java里的this难以理解的多,究其根本原因我个人觉得有三个原因:
原因一:javascript是一个函数编程语言,怪就怪在它也有this指针,说明这个函数编程语言也是面向对象的语言,说的具体点,javascript里的函数是一个高阶函数,编程语言里的高阶函数是可以作为对象传递的,同时javascript里的函数还有可以作为构造函数,这个构造函数可以创建实例化对象,结果导致方法执行时候this指针的指向会不断发生变化,很难控制。
原因二:javascript里的全局作用域对this指针有很大的影响,由上面java的例子我们看到,this指针只有在使用new操作符后才会生效,但是javascript里的this在没有进行new操作也会生效,这时候this往往会指向全局对象window。
原因三:javascript里call和apply操作符可以随意改变this指向,这看起来很灵活,但是这种不合常理的做法破坏了我们理解this指针的本意,同时也让写代码时候很难理解this的真正指向
上面的三个原因都违反了传统this指针使用的方法,它们都拥有有别于传统this原理的理解思路,而在实际开发里三个原因又往往会交织在一起,这就更加让人迷惑不解了,今天我要为大家理清这个思路,其实javascript里的this指针有一套固有的逻辑,我们理解好这套逻辑就能准确的掌握好this指针的使用。
我们先看看下面的代码:
<script type="text/javascript"> this.a = "aaa"; console.log(a);//aaa console.log(this.a);//aaa console.log(window.a);//aaa console.log(this);// window console.log(window);// window console.log(this == window);// true console.log(this === window);// true </script>
在script标签里我们可以直接使用this指针,this指针就是window对象,我们看到即使使用三等号它们也是相等的。全局作用域常常会干扰我们很好的理解javascript语言的特性,这种干扰的本质就是:
在javascript语言里全局作用域可以理解为window对象,记住window是对象而不是类,也就是说window是被实例化的对象,这个实例化的过程是在页面加载时候由javascript引擎完成的,整个页面里的要素都被浓缩到这个window对象,因为程序员无法通过编程语言来控制和操作这个实例化过程,所以开发时候我们就没有构建这个this指针的感觉,常常会忽视它,这就是干扰我们在代码里理解this指针指向window的情形。
干扰的本质还和function的使用有关,我们看看下面的代码: