粗略的看过了<<javascript高级程序设计>>,感觉收获很多,于是乎,拿起各家公司的javascript面试题,顿时被试题强暴了,真心感觉自己还是对javascript有太多不明白,javascript的语法宽松,就导致有许多特殊的地方,javascript有基于原型的面向对象。也是非常值得玩味的地方。
今天,我们来说说new。看代码
var C = function(name){ this.name = name; } var Person = new C('11'); //var Person = new C; 这种调用方式其实就是var Person = new C(),不传参数
alert(Person.name)
书面关于new的解释如下:
当使用new关键字来调用构造函数时,执行上下文从全局对象(window)变成一个空的上下文,这个上下文代表了新生成的实例。
网站上也有给出介绍
new的过程可以分为3步
1.创建一个新对象,var Person
2.让实例Person的_proto_属性指向C.prototype
3.C.call(Person)
第2步,我们会在谷歌等调试程序中看到,第3步其实就是借用了C的构造器,使得实例拥有它的成员
上图是谷歌的断点调试,我们可以看到,Person中的构造器是C,它继承了C的name属性。因为C是一个function,本质上是Object。所以C的原型应该是Object,那Person的_proto_属性也指向它。
可能网站的解释比较通俗一点,我们再来看书面的解释,大家注意一点,那就是执行上下文从全局对象(window)变成一个空的上下文,为什么执行上下文开始会是全局对象了,看代码吧
var name = 1 var C = function(){ var name = 2; var K = function(name){ this.name = name; } } var Person = new C(); C();
我们还有断点调试,查看一下K中this到底是什么
执行var Person = new C();时this指向C
执行C()时,this指向window
this的指向问题,<<javascript高级程序设计>>中定义如下
在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this就等于那个对象。
如下代码
var name = 1; var C = function(){ var name = 2; function B(){ alert(name); } B(); } C();
显示是2,函数里面套函数,大家最直观的感觉就是闭包。没错,是闭包。ok,修改一下代码,如下会输出什么
var name = 1; var C = function(){ var name = 2; function B(){ alert(this.name); } B(); } C();
这个显示1,我这里讲一下,我当时分析的一个错误观点。理解透彻的朋友可以跳过。
B是在C函数中声明的,意味着B存在于C函数的上下文中,由于有一种在全局环境中定义的属性和方法,都可以使用window.XX来调用,所以当时的我天真的以为B是C的一个方法,这个就大错特错了。很明显B如此声明根本就不是C的方法,根据<<javascript高级程序设计>>中对this的定义,B方法中的this,应当属于把它当成方法调用的那个对象。肯定不是C,所以答案不是2.
书中对B函数的调用者为什么是全局,并没有分析太透彻,我在有一页中看到在之中的匿名函数调用者也是全局,自执行的函数也是。再看代码
var name = 1; var C = function(){ var name = 2; function B(){ alert(this.name); } B(); } var Person = new C();
还是显示1,书中讲到new运算符改变了函数的执行上下文。执行上下文从全局变量变成了一个空上下文,这个上下文代表了新生成的实例。当程序执行到function B(){}的最后一个}时,this是指向Person实例,也就是它的构造器C,但当程序执行B()时,由于B并不是C的方法,所以B中的this又指向了window,大家可能动手试一试。
这里我们也就明白了书中讲new的过程了。
ok,下面再补一个代码
var C = function(){ var klass = function(){ this.init.apply(this,arguments); }; klass.prototype.init = function(){ alert(1); }; return klass; } var Person = new C();
这是一种设计模式,<<javascript高级程序设计>>中叫寄生构造函数模式,如果当时读这个,我真心不会有太多印象,死记模式的优缺点不是件好事。
在这种,既return,又new的节奏,可能让人摸不着头脑,仔细分析。在构造函数不返回值的情况下,默认返回新对象的实例,这里通过在构造函数的末尾添加return,相当于重写的返回值,这里我们很清楚,klass跟构造器C根本没有什么关系。之前我们也都提到了。
ok,时间不多,字数刚好。以上是本人的一点小研究,有不对的地方,大家指点。
结束语:
javascript是座冰山,我能看到的只是冰山一角。