[TOC]
## 构造函数
所有引用类型都有构造函数
```
//构造函数一般以大写字母开头.所以一般判断是否是构造函数,可以通过首字母大写判断.
function Foo(name, age){
this.name= name
this.age= age
this.class = ' class-1'
// return this//默认有这一行
}
var f= new Foo('zhangsan, 20);
//varf1= new Foo(Lisi,22); //创建多个对象
```
## 构造函数-扩展
```
var a={} //其实是vara= new Object0的语法糖
var a=[] //其实是vara= new Array的语法糖
function Foo{} //其实是 var foc= new Function()
```
> 使用 instanceof判断一个函数是否是一个变量的构造函数
## 原型规则和示例
- 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了"null"意外)
```js
//什么是可自由扩展属性
var obj= {}; obj.a= 100;
var arr=[]; arr.a= 100;
function fn(){}; fn.a=100;
```
- 所有的引用类型(数组、对象、函数),都有一个`__proto__`(隐式原型)属性,属性值是一个普通的对象
```
console. Log(ob]._proto__)
console. log(arr._proto__)
console. log (fn.__proto__)
```
- 所有的**函数**,都有一个 `prototype`(显示原型)属性,属性值也是一个普通的对象
```js
console.log(fn.prototype)
```
- 所有的引用类型(数组、对象、函数),`_ proto_`属性值指向它的构造函数的" prototype“属性值
```js
console.log(obj.__proto__===Object. prototype ) //对象的__proto__
```
- 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的`_ proto_`(即它的构造函数的prototype)中寻找。
```js
//构造函数
function Foo(name, age){
this.name = name;
}
Foo.prototype.alertname= function (){
alert(this.name)
}
//创建示例
var f= new Foo( 'zhangsan')
f.printname= function (){
console.log(this.name)
}
//测试
f.printname()
f.alertname()
```
- 循环对象自身的属性
```js
var item
for (item in f ){
//高级浏览器已经在 for in中屏蔽了来自原型的属性
//但是这里建议大家还是加上这个判断,保证程序的健壮性
if (f.hasownProperty(item)){//判断是否是自身的属性
console.log(item)
}
}
```
## 原型链
```
//构造函数
function Foo(name, age){
this.name = name;
}
Foo.prototype.alertname= function (){
alert(this.name)
}
//创建示例
var f= new Foo( 'zhangsan')
f.printname= function (){
console.log(this.name)
}
//测试
f.printname()
f.alertname()
f.toString() //要去f,_ proto__. __proto__中查找
```
![](images/16D7719E-648D-4E35-98C1-00D961A13211.jpg)
## instanceof
用于判断引用类型属于哪个构造函数的方法
```
f.instanceof Foo的判断逻辑是
f的_ proto_一层一层往上,能否对应到 Foo.prototype
再试着判断 f instanceof object
```
### 真题
如何准确判断一个变量是数组类型
```
var arr=[];
arr instanceof Array // true
typeof arr // object, typeof是无法判断是否是数组的
```