[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类的理解和使用