Webcourse/13-前端面试/01-面试必看/05-01.创建对象和原型链.md
2020-04-19 18:24:43 +08:00

191 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 前言
### 面向对象的三大特性
- 封装
- 继承
- 多态
### 原型链的知识
原型链是面向对象的基础是非常重要的部分有以下几种知识
- 创建对象有几种方法
- 原型构造函数实例原型链
- `instanceof`的原理
- new 运算符
## 创建对象有几种方法
### 方式一字面量
```javascript
var obj11 = {name: 'qianguyihao'};
var obj12 = new Object(name: 'qianguyihao'); //内置对象(内置的构造函数)
```
上面的两种写法效果是一样的因为第一种写法`obj11`会指向`Object`
- 第一种写法是字面量的方式
- 第二种写法是内置的构造函数
### 方式二通过构造函数
```javascript
var M = function (name) {
this.name = name;
}
var obj3 = new M('smyhvae');
```
### 方法三Object.create
```javascript
var p = {name:'smyhvae'};
var obj3 = Object.create(p); //此方法创建的对象,是用原型链连接的
```
第三种方法很少有人能说出来这种方式里obj3是实例p是obj3的原型name是p原型里的属性构造函数是`Objecet`
![](http://img.smyhvae.com/20180306_1633.png)
## 原型构造函数实例以及原型链
![](http://img.smyhvae.com/20180306_1540.png)
PS任何一个函数如果在前面加了new那就是构造函数
### 原型构造函数实例三者之间的关系
![](http://img.smyhvae.com/20180306_2107.png)
- 1构造函数通过 new 生成实例
- 2构造函数也是函数构造函数的`prototype`指向原型所有的函数有`prototype`属性但实例没有 `prototype`属性
- 3原型对象中有 constructor指向该原型的构造函数
上面的三行代码演示
```
var Foo = function (name) {
this.name = name;
}
var foo = new Foo('smyhvae');
```
上面的代码中`Foo.prototype.constructor === Foo`的结果是`true`
![](http://img.smyhvae.com/20180306_2120.png)
- 4实例的`__proto__`指向原型也就是说`foo.__proto__ === Foo.prototype`
声明所有的**引用类型**数组对象函数都有`__proto__`这个属性
`Foo.__proto__ === Function.prototype`的结果为true说明Foo这个普通的函数是Function构造函数的一个实例
### 原型链
**原型链的基本原理**任何一个**实例**通过原型链找到它上面的**原型**该原型对象中的方法和属性可以被所有的原型实例共享
Object是原型链的顶端
原型可以起到继承的作用原型里的方法都可以被不同的实例共享
```
//给Foo的原型添加 say 函数
Foo.prototype.say = function () {
console.log('');
}
```
**原型链的关键**在访问一个实例的时候如果实例本身没找到此方法或属性就往原型上找如果还是找不到继续往上一级的原型上找
### `instanceof`的原理
![](http://img.smyhvae.com/20180306_2209.png)
`instanceof`**作用**用于判断**实例**属于哪个**构造函数**
`instanceof`**原理**判断实例对象的`__proto__`属性和构造函数的`prototype`属性是否为同一个引用是否指向同一个地址
**注意1**虽然说实例是由构造函数 new 出来的但是实例的`__proto__`属性引用的是构造函数的`prototype`也就是说实例的`__proto__`属性与构造函数本身无关
**注意2**在原型链上原型的上面可能还会有原型以此类推往上走继续找`__proto__`属性这条链上如果能找到 instanceof 的返回结果也是 true
比如说
- `foo instance of Foo`的结果为true因为`foo.__proto__ === Foo.prototype`为true
- **`foo instance of Objecet`的结果也为true**因为`Foo.prototype.__proto__ === Object.prototype`为true
但我们不能轻易的说`foo 一定是 由Object创建的实例`这句话是错误的我们来看下一个问题就明白了
### 分析一个问题
**问题**已知A继承了BB继承了C怎么判断 a 是由A**直接生成**的实例还是B直接生成的实例呢还是C直接生成的实例呢
分析这就要用到原型的`constructor`属性了
- `foo.__proto__.constructor === Foo`的结果为true但是 `foo.__proto__.constructor === Object`的结果为false
所以 consturctor判断就比用 instanceof判断更为严谨
## new 运算符
当new Foo()时发生了什么
1创建一个**新的空对象实例**
2将此空对象的隐式原型指向其构造函数的显示原型
3执行构造函数传入相应的参数如果没有参数就不用传同时 this 指向这个新实例
4如果返回值是一个新对象那么直接返回该对象如果无返回值或者返回一个非对象值那么就将步骤1创建的对象返回
参考JS高程6.2.2
## 类继承和原型继承的区别
```javascript
```