`
simohayha
  • 浏览: 1386587 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

在javascript中如何判断一个方法是new调用还是一般调用

阅读更多
在看The.Art.and.Science.of.JavaScript 的时候,看到了这个问题,就是在javascript中如何判断一个方法是new调用还是一般调用,在书中给出的代码是

function Element(){
   if(this==window || 'Element' in this){
      console.log("normal");
}else{
     console.log("new");
}

}


可是这个代码不能解决两个问题:

1比如加上下面的代码:

 Element.prototype.Element=1; 


这时如果调用new Element()时,由于Element 已经存在于this里面,因此会打印出normal;

这个很好解决。我是这样写的:

function Element(){
if(this.__proto__==Element.prototype)
{console.log("new");}else{console.log("normal");}}


可是这时又有了第二个问题。

比如下面的代码:

var test= new Element();

test.temp=Element;

test.temp();


这时的调用,也应该是normal的调用,可是依然打印出new.

实在想不出来怎么解决第二种情况,因此发出来看那位能够解决这个问题.

分享到:
评论
12 楼 achun 2008-05-04  
笨笨狗 写道
achun 写道
LS最后写的这个,感觉比我写的那个有水准.
this.name VS arguments.callee
呵呵,当然是arguments.callee看上去更美丽了.


不止是看上去更美丽,先来看你的代码:


function Element(){    
   if(this.name==undefined){    
       console.log("new");    
   }else{    
      console.log("normal");    
   }  
}  
 


试试在调用这段代码之前干这事:


var name;
Element(); //出现意外了吧,呵呵



确实,偶这个是错误的.理论上就有问题.
IE不过,FF过了,是FF的BUG?
11 楼 yyliuliang 2008-05-04  
this.toString().match(/( \w+)/)[0]
10 楼 笨笨狗 2008-05-04  
achun 写道
LS最后写的这个,感觉比我写的那个有水准.
this.name VS arguments.callee
呵呵,当然是arguments.callee看上去更美丽了.


不止是看上去更美丽,先来看你的代码:


function Element(){    
   if(this.name==undefined){    
       console.log("new");    
   }else{    
      console.log("normal");    
   }  
}  
 


试试在调用这段代码之前干这事:


var name;
Element(); //出现意外了吧,呵呵


9 楼 笨笨狗 2008-05-04  
笨笨狗 写道



var t = new Test();
t.Test = Test;
t.Test();





而且,就算不阻止构造函数实例化对象,换个角度来看,这段代码也没超出我们的预期,因为把Test赋值给一个对象作为其属性然后调用,实际上已经不再算是原始的构造函数了吧,虽然也是引用……
8 楼 achun 2008-05-04  
LS最后写的这个,感觉比我写的那个有水准.
this.name VS arguments.callee
呵呵,当然是arguments.callee看上去更美丽了.
7 楼 笨笨狗 2008-05-04  
对于我的需求,也就是“当函数被用作new的时候,抛出异常”来说,我上面的解决办法就已经很完美了,因为都不存在之前被new出来的实例对象,那么后面那个故意让其失效的方法就不能运作了,所以这样就够了:

function Test(){
    if(this instanceof arguments.callee){
        throw new Error("不能做实例化操作!");
    }
    console.log("普通调用");
}


因为此时已经不可能有一个Test的实例对象来调用本身了,也就是说下面这段代码被避免了:


var t = new Test();
t.Test = Test;
t.Test();



如果不阻止构造函数实例化对象,那么上面的代码是可以运行的,但是现在没有意外了:)
6 楼 s79 2008-05-04  
自造构造函数不使用new,直接return新建对象,这样new不new是一样的,就省的费劲判断了。o(∩_∩)o...
5 楼 csf178 2008-05-03  
再怎么写也只能找到更多的必要条件 没有充分条件

至于这个 this.testTimeStamp=new Date().getTime(); 纯粹是自找麻烦
想要伪造很容易 delete了testTimeStamp怎么办?
4 楼 afcn0 2008-05-03  
讨论下这个问题,new之前创建了一个空对象,并且隐藏继承了构造函数的原形,然后以这个空对象为this执行构造函数,如果构造函数当中没有return object,那就是返回this对象,所以其实就是普通的运行构造函数,想要区分,比较好的就是

function test(){
if (this instanceof arguments.callee && (!this.testTimeStamp || this.testTimeStamp<new Date().getTime())) 
{
this.testTimeStamp=new Date().getTime();
..........
}
else
{
一般.......
}
}

3 楼 achun 2008-05-03  
我这样写:
function Element(){  
  if(this.name==undefined){  
      console.log("new");  
}else{  
     console.log("normal");  
}
}
2 楼 hax 2008-02-27  
我个人一直是这么写的:

function ClassA() {
  assert (this instanceof ClassA);
  // constructing our instance
}

有时候也会这样:

function CustomError(msg) {
  if (this instanceof CustomError) {
    // constructiing...
  } else {
    return new CustomError(msg);
  }
}
1 楼 笨笨狗 2008-02-27  
楼主第二个方法,那个__proto__属性只有ff支持,所以也不完美。
一开始我这么写
function Element(){  
    if(this.constructor===arguments.callee){ // this instanceof arguments.callee 也是一样的效果
        console.log("new");
    }else{
        console.log("normal");
    }
} 

看起来还不错,但是:
a = new Element;
a.Element = Element;
a.Element() //完蛋,告诉我是new

然后,又想,既然new的话,this肯定是个新对象,这个对象不会是window,也不会是window的属性,那好,这样
function Element(){ 
    var flag = "new"
    if(this===window){
       flag = "normal";
    }else{
        for(var i in window){
            if(this===window[i]){
                flag = "normal";
            }
        }
    }
    console.log(flag)
} 

貌似不错,但是,但是:
a = {b:{Element:Element}}
a.b.Element() //依然是new!现在this是b,当然不在window下,new的this肯定不在window下,但是反过来说不一定,晕倒



由于js中的函数是游离的,this可以动态改变,所以要真正解决这个问题应该很困难,但是如果限定在一定的范围内,比如说,不在对象引用构造函数本身,那this instanceof arguments.callee这样的判断就足够了。之所以探讨这个问题,是因为看了Pro javascript design paterns,里面有实现Interface,但是我觉得他那个检测太弱了,准备自己实现一个更严格的Interface,用来限定某个对象的属性类型、方法参数个数以及返回值。这样又引出一个问题,我们知道java里面的Interface是不可以实例化的,所以js实现的话需要判断一下Interface这个函数是不是被new了,如果是,就抛异常……

相关推荐

    JavaScript中判断函数是new还是()调用的区别说明

    具名函数的各种调用方式 在之前篇幅中已经介绍过了。这篇看看如何判断一个函数是被new调用的,还是被其它方式调用的。

    JavaScript程序设计课件:函数的调用方式.pptx

    JavaScript程序设计 函数的调用方式 ...使用点语法可以调用一个方法。 5.2.2 函数的调用方式 2、函数的调用方式 call 和 apply 是 Function 的原型方法,它们能够将特定函数当做一个方法绑定到指定对象上,并进

    在JavaScript中实现链式调用的实现

    链式调用在 JavaScript 语言界很常见,如 jQuery 、 Promise 等,都是使用的链式调用。链式调用可以让我们在进行连续操作时,写出更简洁的代码。 new Promise((resolve, reject) =&gt; { resolve(); }) .then(() =...

    【JavaScript源代码】JavaScript中的几种继承方法示例.docx

    JavaScript中的几种继承方法示例  1.原型链继承  原理: 子类原型指向父类实例对象实现原型共享,即Son.prototype = new Father()。 这里先简单介绍下原型 js中每个对象都有一个__proto__属性,这个属性指向的...

    javascript学习笔记.docx

    f) 继承:只是在查询一个属性时自动发生,而不会在写属性时发生,就是说单写一个父类的属性时,JavaScript环境会为对象本身创建一个同名的属性,从此该属性就覆盖了父类中的属性。 12) 创建一个数组可用 new Array()...

    javascript中使用new与不使用实例化对象的区别

    我们先来看个实例 function Me(name,age,job){ this.name = name; this.age = age; this.job = job; } ...请问这以下两种实例化对象方式有什么区别呢?...JavaScript 中并没有真正的类,但JavaScript 中有

    JavaScript四种调用模式和this示例介绍

    JavaScript调用时除了声明时定义的形参外,每个函数接受两个附加参数:this 和arguments,this在面向对象编程中非常重要,它取决于调用模式。 JavaScript有四种调用模式,方法调用模式,函数调用模式,构造器调用...

    Prototype_1.6 JavaScript代码和中文帮助手册

     在prototype.js中,prototype对象是实现面向对象的一个重要机制。  每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一...

    javascript文字编辑器

    一个可以用的js文字编辑器, 调用方法:&lt;input type="hidden" name="new" maxlength="5000"&gt; &lt;script type="text/javascript" src="KindEditor.js"&gt; &lt;script type="text/javascript"&gt; var editor = new ...

    rpc:调用在其他JavaScript窗口进程中运行和运行的函数

    WranggleRpc是一个JavaScript / TypeScript库,用于调用在其他窗口/进程中运行的代码。 这在构建时特别有用: 具有内容页面窗口,弹出窗口和必须交互的服务/背景窗口的浏览器扩展 电子应用程序及其节点和浏览器...

    JavaScript面向对象

    在JavaScript中定义JavaScript对象有两种方式: 方式一: var Book ={ getBookName:function(){ alert&#40;"获取书的名称"&#41; ; } }; 方式二 var oBook = function(){}; oBook.getBookName=...

    javascript简单链式调用案例分析

    本文实例讲述了javascript简单链式调用方法。分享给大家供大家参考,具体如下: jQuery用的就是链式调用。像一条连接一样调用方法。 链式调用的核心就是return this;,每个方法都返回对象本身。 下面是简单的模拟...

    javascript 函数限制调用代码

    函数: 代码如下: function throttle(fn,ms) { ... } 参数 fn : 传入的函数/方法 参数 ms:每次函数调用时的间隔(毫秒为单位),如输入2000,函数在2秒内不会重复触发。 附一初始化例子 代码如下: document.getElementById

    不得不看之JavaScript构造函数及new运算符

    当通过new来创建一个新对象时,JS底层将新对象的原型链指向了构造函数的原型对象,于是就在新对象和函数对象之间建立了一条原型链,通过新对象可以访问到函数对象原型prototype中的方法和属性。 和其他高级语言一样 ...

    一个精美的javascript弹出层提示框,支持任意浏览器,基于jquery,定位准确!

    一个精美的javascript 对话,在N种浏览器测试下均无问题,调用方便,支持传入iframe,文字信息,可以设置是否调用层遮罩,是否可以拖动。定位准确, 调用方法,var dialog = new Dialog({ text: "我是内容", w: 300, ...

    go-node:使用Node.js在Go中运行Javascript

    去节点 使用Node.js在Go中运行Javascript。正在安装 go get -u github.com/tidwall/go-node例子创建一个Node.js VM并运行一些Javascript。 vm := node . New ( nil )vm . Run ( "iLoveTheJS = true" );youLoveIt := ...

    JavaScript使用function定义对象并调用的方法

    JS中你可以通过函数的方式定义对象,下面的JS代码定义了一个movie的函数对象,然后通过new的方法声明对象,调用起来也非常简单。 [removed] function movie(title, director) { this.title = title; this....

    【JavaScript源代码】JavaScript中的Proxy对象.docx

    handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理proxy的行为。  描述 Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都...

    DWR.xml配置文件说明书(含源码)

    如果你想远程调用一个creator的静态方法,并且creator是new类型.因为调用远程bean的方法前DWR不会检测将要执行的方法是不是静态方法,如果是静态方法那么creator就不用创建.这种机制可以适用任何类型的creator,但new...

Global site tag (gtag.js) - Google Analytics