JQ中发现的,jQuery.Event类。估计作者是为了减少代码量。定义一个类,但不用new关键字去创建该类对象,而使用方法调用()方式去创建该对象。
?
多数时候我们是这样写类,然后使用new创建对象的。
?
function Person(name,age){ this.name=name; this.age=age; } Person.prototype={ setName : function(n){this.name=n;}, getName : function(){return this.name;} } var p = new Person('jack',25);
?
改成这样的
function Person(name,age){ //条件改为(this==window)或(this==self)或(this.constructor!=Object) if(!this.setName){ return new Person(name,age); } this.name=name; this.age=age; } Person.prototype={ setName : function(n){this.name=n;}, getName : function(){return this.name;} } var p = Person('jack',25);?
注意该类较最上面的写类方式中多了以下
?
if(!this.setName){ return new Person(name,age); }?
好,创建类的实例(对象)方式也变成了如下:
?
var p = Person('jack',25);
?
这种创建方式(函数调用)较上面的少了“new_”,new和空格,实际上是在类内部new了。而这样方式每次创建对象可以减少4个byte。
?
如果把类内部的if判断条件换成非prototype上的属性,如this.name。程序会提示出错:too much recursion
?
function Person(name,age){ if(!this.name){ return new Person(name,age); } this.name=name; this.age=age; } Person.prototype={ setName : function(n){this.name=n;}, getName : function(){return this.name;} } var p = Person('jack',25);?
?
?
1 楼
lixinlixin2008
2010-04-07
呵呵,学到了,省的字节虽然少,不过对于追求极致的人来说,还是有用的,对prototype的执行顺序真是理解深刻...
2 楼
weiqingfei
2010-04-08
这个判断有缺陷
如果全局有个setName属性或者方法,这个判断就会失效。
if(!this.setName){ return new Person(name,age); }
如果全局有个setName属性或者方法,这个判断就会失效。
3 楼
zhouyrt
2010-04-08
weiqingfei 写道
这个判断有缺陷
如果全局有个setName属性或者方法,这个判断就会失效。
if(!this.setName){ return new Person(name,age); }
如果全局有个setName属性或者方法,这个判断就会失效。
感谢提醒,但这是为什么呢?即使加了一次闭包仍然失效。
4 楼
weiqingfei
2010-04-08
直接调用Person方法时,这儿的this指的是window,只有在new Person的时候,this才指的是Person的一个实例,原本这儿就是为了判断是直接调用,还是在new。但是当window里也有这个方法或者属性的时候,就失效了。
5 楼
zhouyrt
2010-04-09
weiqingfei 写道
直接调用Person方法时,这儿的this指的是window,只有在new Person的时候,this才指的是Person的一个实例,原本这儿就是为了判断是直接调用,还是在new。但是当window里也有这个方法或者属性的时候,就失效了。
说的有道理。
把条件改成以下就可以了,不怕同名的全局函数了。
1,this==window
2,this===window
3,this==self
4,this!=Object
6 楼
蔡华江
2010-04-09
个人感觉,这个会导致思路上混乱。
7 楼
weiqingfei
2010-04-09
zhouyrt 写道
weiqingfei 写道
直接调用Person方法时,这儿的this指的是window,只有在new Person的时候,this才指的是Person的一个实例,原本这儿就是为了判断是直接调用,还是在new。但是当window里也有这个方法或者属性的时候,就失效了。
说的有道理。
把条件改成以下就可以了,不怕同名的全局函数了。
1,this==window
2,this===window
3,this==self
4,this!=Object
有时候,这个方法的声明,不一定会放在全局(也就是window)上,所以我觉得如果是内部使用的话也就算了,开放给用户用的话不大合适。
8 楼
aninfeel
2010-04-09
没意义,还会是代码的可读性变差。
9 楼
蔡华江
2010-04-09
还有一个问题就是,这种写法会带来call与apply方法的不正确运行
10 楼
zhouyrt
2010-04-09
weiqingfei 写道
zhouyrt 写道
weiqingfei 写道
直接调用Person方法时,这儿的this指的是window,只有在new Person的时候,this才指的是Person的一个实例,原本这儿就是为了判断是直接调用,还是在new。但是当window里也有这个方法或者属性的时候,就失效了。
说的有道理。
把条件改成以下就可以了,不怕同名的全局函数了。
1,this==window
2,this===window
3,this==self
4,this!=Object
有时候,这个方法的声明,不一定会放在全局(也就是window)上,所以我觉得如果是内部使用的话也就算了,开放给用户用的话不大合适。
诚如jq中jQuery.Event的定义,Event不是全局的而是挂在jQuery上的,这样定义的用!this.preventDefault判断没有问题。或者说即使定义了全局的preventDefault(函数/变量),这个条件也不会失效的。因为jQuery.Event类中的this指向的是jQuery而非window。
因此,这种写法有几个前提。
1,是在定义一个类
2,用new去创建这个类的实例
3,追求极致的精简代码
11 楼
zhouyrt
2010-04-09
蔡华江 写道
还有一个问题就是,这种写法会带来call与apply方法的不正确运行
可以运行,只要正确的传了上下文参数。但这样违背了每次创建对象减少byte的初衷。
以下的p0,p1,p2分别是(),call,apply调用,会发现call,apply创建对象的代码比new还多。
function setName(){}; function Person(name,age){ if(this==window){//this==self or this.constructor != Object return new Person(name,age); } this.name=name; this.age=age; } Person.prototype.setName = function(n){this.name=n;}; Person.prototype.getName = function(){return this.name;} var p0 = Person('jack',25); var p1 = Person.call(window,'jack',25); var p2 = Person.apply(window,['jack',25]);
12 楼
蔡华江
2010-04-09
zhouyrt 写道
蔡华江 写道
还有一个问题就是,这种写法会带来call与apply方法的不正确运行
可以运行,只要正确的传了上下文参数。但这样违背了每次创建对象减少byte的初衷。
以下的p0,p1,p2分别是(),call,apply调用,会发现call,apply创建对象的代码比new还多。
function setName(){}; function Person(name,age){ if(this==window){//this==self or this.constructor != Object return new Person(name,age); } this.name=name; this.age=age; } Person.prototype.setName = function(n){this.name=n;}; Person.prototype.getName = function(){return this.name;} var p0 = Person('jack',25); var p1 = Person.call(window,'jack',25); var p2 = Person.apply(window,['jack',25]);
是不是我要这样认为,你在楼上举的特例是能正常运行的。
可是我调用call与apply时,通常不是放置window作为scope的,如果是那样的话,我直接使用window就行了。
也许我会使用一个Student类来调用,if(this==window)的验证岂不是无效的。
13 楼
weiqingfei
2010-04-09
zhouyrt 写道
weiqingfei 写道
zhouyrt 写道
weiqingfei 写道
直接调用Person方法时,这儿的this指的是window,只有在new Person的时候,this才指的是Person的一个实例,原本这儿就是为了判断是直接调用,还是在new。但是当window里也有这个方法或者属性的时候,就失效了。
说的有道理。
把条件改成以下就可以了,不怕同名的全局函数了。
1,this==window
2,this===window
3,this==self
4,this!=Object
有时候,这个方法的声明,不一定会放在全局(也就是window)上,所以我觉得如果是内部使用的话也就算了,开放给用户用的话不大合适。
诚如jq中jQuery.Event的定义,Event不是全局的而是挂在jQuery上的,这样定义的用!this.preventDefault判断没有问题。或者说即使定义了全局的preventDefault(函数/变量),这个条件也不会失效的。因为jQuery.Event类中的this指向的是jQuery而非window。
因此,这种写法有几个前提。
1,是在定义一个类
2,用new去创建这个类的实例
3,追求极致的精简代码
嗯,其实是一样的,要保证object jQuery里面没有属性或者方法preventDefault,否则也同样会失效。
但是用户使用jQuery.extend是可以添加这个方法或者属性的。
我没用过jQuery,只是刚开始看它的代码,还不知道jQuery.Event到底怎么用,如果可以开放给用户的话,这个地方就要注意了。
14 楼
lgzjw
2010-04-11
外表看来少了4byte的也就是new 少了,并且window下also不能有if判断的同名对象存在.