很奇怪的是不少书或资料没有把这个事情讲清楚。javascript
关键就是在于没有一个总体的思惟技术模式,问题被隔离了因此反而不容易理解。java
咱们先看this,这是js的关键字,指示函数的上下文对象。编程
这里问题就来了,好比:安全
var obj = {}; obj.name = 'test'; obj.output = function () { console.log(this.name); }; obj.output();
this指定了上下文对象,固然若是没有指定就会指定到全局变量,window,这就是问题的根源所在。因此最好的解决方案,就是使用'use strict'严格模式,一但出错,比较容易定位问题。函数
在不用严格模式下,咱们看看问题出如今哪里?this
重命名变量时:prototype
好比上面,console.log(obj.name),不用this的话,那么在其它代码里obj被另外变量定义,明显要出错。但用了this,代码环境一变就出问题。对象
好比咱们把这个对象重构成构造函数:blog
function Obj(name) {ip
....
都要使用this关键字。
可是构造函数也是个函数,稍不注意就会当成普通函数调用。不加new,变成这样。
Obj('test')...
这时构造函数被错误运行,而它竟争不会出错,为何呢?在非严格模式下,构造函数的this指向了全局的window,这就是JS最大的缺陷。不只不能获得正确的运行结果,还污染了全局。在大量的JS里,误调用一个构造函数就是灾难性的结果。
为何面向对象的程序好比C#,Java不会有这个问题?由于它们使用class关键字,class在定义阶段没法使用(除非明肯定义的static属性和方法)
可见,JS的这个严重的this,不只是全局变量的问题,还影响了整个构造函数的面向对方方式编程,因此安全的方式写构造函数是必须的,就是不用new,也能构造。
固然'use strict'只是治标。治本就是要让new 和不new都获得一致的结果。
JS的构造函数,若是直接运行,那么返回结果就是对象,this定义的对象被抛弃,很特别的一点。因此干脆就不用定义this用new,直接使用返回对象。
function pClass() { this.Name = 'test'; this.output = function () { console.log(this.Name); } return new pClass(); } var p1 = pClass(); var p2 = new pClass(); p1.output(); p2.output();
不用new,却是对了,第一个问题获得解决,但若是再new就会变成嵌套调用。出错。很明显,出错是由于this,因此咱们在内部,直接定义对象返回,作成真正的“构造函数”
function pClass() { return { Name: 'test', output: function () { console.log(this.Name); } } } var p1 = pClass(); var p2 = new pClass(); p1.output(); p2.output();
这问题又来了,直接返回对象避免了this的问题,但明显重复,好比p1,p2使用了两个实例的output方法,这是不能够容忍的。
因此这就致使了JS在处理对象的建立方面没法提供有效的机制,this和new不匹配,完全的解决方案就是ES6,引入class关键字,不然的话,无论怎么建立都没有完美的解决方案,并且代码啰嗦。
在ES5上,次好的解决方案是:
1.引入'use strict',防止错误的构造函数及this
2.构造函数首字母大写,其它的一概驼峰,经过命名来区分
3.建立对象一概使用new,并使用简单的prototype模式
4.非new形式尽可能使用module模式
5.最关键的地方,JS对象就不是长项,面向对象编程也并不是最佳方式,应该优先考虑组合模式,把对象和方法体分开,这从根源上解决JS的对象弱点。