💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] >[success] # 明确函数的多重用途 ~~~ JS 为函数提供了两个不同的内部方法: 'Call' 与 'Constructor' 。当函数未使用 'new' 进行调用时, 'call'方法会被执行,运行的是代码中显示的函数体。而当函数使用 'new' 进行调用时,'Constructor' 方法则会被执行,负责创建一个被称为新目标的新的对象,并且使用该新目标作为'this'去执行函数体。 '拥有 Constructor 方法的函数被称为构造器',记住不是所有函数都有'Constructor'方法,因此不是所有函数 都可'new'来实例化对象来调用,'箭头函数'就没有'Constructor'方法 ~~~ ~~~ function Person(name){ this.name = name } var person = new Person('aaa') var notPerson = Person('aaa') console.log(person) console.log(notPerson) // undefined console.log(Person.name) // 非严格模式下'Person'会有name属性 ~~~ <br/> >[success] ## ES5判断函数被调用 ~~~ 在'ES5'中判断'函数'是不是使用了'new'来调用(即作为构造器),或者说判断该函数是否作为'构造函数'被 调用,可以使用'instanceof' 来判断,例子如下: ~~~ ~~~ function Person(name){ if(this instanceof Person){ this.name = name // 如果通过 new 方式调用 } else { throw new Error('必须通过new关键字来调用Person。') } } let person = new Person('测试一下') // { name: '测试一下 } Person('测试一下') // 报错:必须通过new关键字来调用Person。 ~~~ <br/> >[success] ### 特殊场景 ~~~ 还有一种特殊情况是判断不出来的,如下,`person2`通过`call`方法来把this指向改变成了`person`实例, 对于函数来讲,是无法区分你是通过`Person.call`、`Person.apply`、还是`new`实例化对象调用的这个 方法 ~~~ ~~~ function Person(name){ if(this instanceof Person){ this.name = name // 如果通过 new 方式调用 } else { throw new Error('必须通过new关键字来调用Person。') } } let person = new Person('测试一下') // { name: '测试一下 } let person2 = Person.call(person,'测试一下2') ~~~ <br/> >[success] ## ES6判断函数被调用( new.target 元属性 ) ~~~ 'ES6'的'new.target'可以解决判断是否通过'new'的方式调用'构造函数',以防止通过'call'、'apply'方式 调用构造函数。 ~~~ ~~~ function Person (name){ if(typeof new.target !== 'undefined'){ this.name = name } else { throw new Error('必须通过new关键字来调用Person。') } } let person = new Person('测试一下') // {name: '测试一下} let notPerson = Person.call(person, '测试一下2') // 报错: 必须通过new关键字来调用Person。 或者像下面这样也会检测到不是通过'new'的方式调用构造方法 function Person (name){ if(typeof new.target !== 'undefined'){ this.name = name } else { throw new Error('必须通过new关键字来调用Person。') } } function AnotherPerson (name){ Person.call(this, name) } let person = new Person('测试一下') // {name: '测试一下} let anotherPerson = new AnotherPerson('测一下') // 报错: 必须通过new关键字来调用Person。 ~~~