[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。
~~~
- Javascript基礎篇
- Array數組
- 數組插入值
- filter()
- forEach()
- push()
- pop()
- unshift()
- shift()
- valueOf()
- 面向對象思想
- Javascript 面向對象編程(一):封裝
- Javascript面向對象編程(二):構造函數的繼承
- Javascript面向對象編程(三):非構造函數的繼承
- 解構
- 數組的解構賦值
- 對象的解構賦值
- 函數參數解構
- 字符串的解構賦值
- 數值和布爾值的解構賦值
- 圓括號問題
- 字符串.
- split()
- charAt()
- charCodeAt()
- concat()
- indexOf()
- lastIndexOf()
- match()
- replace()
- includes()
- 初識遞歸
- 渲染ul-li樹形結構
- 異步函數解決方案
- 1. callback回調函數
- 2. ES6 - Promise
- JavaScript高級程序設計(書)
- 在html中使用JavaScript
- script標簽的位置
- 延遲腳本
- 異步腳本
- <noscript>元素
- 基本概念
- 嚴格模式
- 變量詳解
- 數據類型
- typeof操作符
- undefined類型
- Null類型
- Boolean類型
- Number類型
- 深入了解ES6(書)
- var 、let 、 const
- 字符串與正則表達式
- 字符串
- 正則表達式
- 函數
- 函數形參默認值
- 使用不具名參數
- 函數構造器的增強能力
- 擴展運算符
- name屬性
- 明確函數的多重用途
- 塊級函數
- 箭頭函數
- 尾調用優化
- 擴展的對象功能
- 對象類別
- 對象字面量語法的擴展
- ES6對象新增方法
- 重復的對象屬性
- 自有屬性的枚舉順序
- 更強大的原型
- 解構:更方便的數據訪問
- 為什么要用解構?
- 對象解構
- 數組解構
- 混合解構
- 參數解構
- Symbol與Symbol屬性
- 創建Symbol
- Symbol的使用方法
- Symbol全局私有屬性
- Symbol與類型強制轉換
- Symbol屬性檢索
- Symbol的一些構造方法
- Set集合與Map集合
- Set集合
- Weak Set集合(弱引用Set集合)
- Map集合
- JS標準內置對象
- Object 構造函數及屬性
- Object 構造方法
- Symbol 內建對象類的函數及屬性
- Set 構造函數及屬性
- Weak Set 構造函數及屬性
- JS雜項
- 類數組對象
- Class類的理解和使用