From 263943371e8a47a797064324091594f173ff0224 Mon Sep 17 00:00:00 2001 From: qianguyihao Date: Tue, 6 Mar 2018 22:22:25 +0800 Subject: [PATCH] add --- 03-JavaScript/10-原型链.md | 269 ++++++++++++++++++++++++++++++++ 06-前端基础/01-页面布局.md | 13 +- 06-前端基础/03-DOM事件的总结.md | 7 +- 06-前端基础/04-HTTP协议.md | 15 +- 06-前端基础/05-原型链.md | 218 ++++++++++++++++++++++++++ 5 files changed, 503 insertions(+), 19 deletions(-) create mode 100644 03-JavaScript/10-原型链.md diff --git a/03-JavaScript/10-原型链.md b/03-JavaScript/10-原型链.md new file mode 100644 index 0000000..a7baefe --- /dev/null +++ b/03-JavaScript/10-原型链.md @@ -0,0 +1,269 @@ + + +## 常见概念 + +- 构造函数 + +- 构造函数-扩展 + +- 原型规则和示例 + +- 原型链 + +- instanceof + +## 构造函数 + +任何一个函数都可以被new,new了之后,就成了构造方法。 + +如下: + +```javascript + function Foo(name, age) { + this.name = name; + this.age = age; + //retrun this; //默认有这一行。new一个构造函数,返回一个对象 + + } + + var fn1 = new Foo('smyhvae', 26); + var fn2 = new Foo('vae',30); //new 多个实例对象 +``` + +与普通函数相比,构造函数有以下明显特点: + +- 用new关键字调用。 + +- 不需要用return显式返回值的,默认会返回this,也就是新的实例对象。 + +- 建议函数名的首字母大写,与普通函数区分开。 + +参考链接: + +- [JavaScript中的普通函数与构造函数](http://www.cnblogs.com/SheilaSun/p/4398881.html) + +当new之后,this会先变成一个空对象,然后通过`this.name = name`来赋值。 + + + + +### 构造函数的扩展 + +20180306_1633.png + +上图中发现,数组、对象、函数也有构造函数,它们的构造函数是Array、Object、funtion。实际开发中,都推荐前面的书写方式。 + + + +## 原型规则 + +原型规则是学习原型链的基础。原型规则有五条,下面来讲解。 + +### 规则1 + +所有的引用类型(数组、对象、函数),都具有对象特性,都可以**自由扩展属性**。null除外。 + +举例: + +20180306_1651.png + + +### 规则2 + +所有的**引用类型**(数组、对象、函数),都有一个`_proto_`属性,属性值是一个**普通的对象**。`_proto_`的含义是隐式原型。 + +20180306_1656.png + +其实,规则2是规则1的特例,只不过,js语法帮我们自动加了 规则2。 + + +### 规则三 + +所有的**函数**(不包括数组、对象),都有一个`protype`属性,属性值是一个**普通的对象**。`protype`的含义是**显式原型**。(实例没有这个属性) + +20180306_1659.png + + +### 规则四 + +所有的**引用类型**(数组、对象、函数),`_proto_`属性指向它的**构造函数**的`protype`值。 + +20180306_1701.png + + +总结:以上四条,要先理解清楚,然后再来看下面的第五条。 + + +### 规则五 + +当试图获取一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的`_proto_`中寻找(即它的构造函数的`protype`)。 + + +`举例代码1`: + + +```javascript + //创建方法 + function Foo(name) { + this.name = name; + } + + Foo.prototype.alertName = function () {// 既然 Foo.prototype 是普通的对象,那也允许给它添加额外的属性 alertName + console.log(this.name); + } + + + var fn = new Foo('smyhvae'); + fn.printName = function () { + console.log(this.name); + } + + //测试 + fn.printName(); //输出结果:smyhvae + fn.alertName(); //输出结果:smyhvae +``` + +上方代码中,虽然 alertName 不是 fn 自身的属性,但是会从它的构造函数的`protype`里面找。 + + +**扩展:**遍历循环对象自身的属性 + +我们知道,`for ... in`循环可以遍历对象。针对上面的那个fn对象,它自身有两个属性:`name`、`printName`,另外从原型中找到了第三个属性`alertName`。现在,如果我们对fn进行遍历,能遍历到两个属性还是三个属性呢? + +答案:两个。因为,**高级浏览器中已经在 `for ... in`循环中屏蔽了来自原型的属性。但是,为了保证代码的健壮性,我们最好自己加上判断**,手动将第三个属性屏蔽掉: + +```javascript + for (var item in fn) { + if (fn.hasOwnProperty(item)) { + console.log(item); + } + } + +``` + + + +## 原型链 + +还是拿上面的``举例代码1``举例,如果此时在最后面加一行代码: + +``` + fn.toString(); //去 fn._proto_._proto 中查找 toString()方法 +``` + +上面的代码中,fn直接调用了 toString()方法,这是因为它通过**原型链**,去`_proto_`的`_proto_`里找到了`Object`,而`Object`是由`toString()`方法的。 + +### instanceof + +格式: + +```javascript + 对象 instanceof 构造函数 +``` + + + +`instanceof`的作用:用于判断**引用类型**属于哪个**构造函数**。 + +例1:判断一个变量是否为数组: `变量 instanceof Array` + +例2: + +```javascript + function Person(){ + } + + //p--->Person.prototype--->Object.prototype--->null + var p = new Person(); + //构造函数的**原型**是否在 p 对象的原型链上! + console.log(p instanceof Person); +``` + +例3: + +```javascript + fn instanceof Foo +``` + +上面这句话,判断逻辑是:**fn 的`_proto_`一层一层往上找,看能否对应到 Foo.prototype**。 + +原型链如下:(重要) + +20180306_1853.png + + +注意,Object这个构造方法的显式原型是null,这是一个特例。 + + + +## 常见题目 + +- 如何准确判断一个变量时数组类型 + +- 写一个原型链继承的例子 + +- 描述 new 一个对象的过程 + +- zepto(或其他框架)源码中如何使用原型链 + + +下面分别讲解。 + +### 题目一:如何准确判断一个变量时数组类型 + +答案: + +```javascript + var arr1 = []; + + console.log(arr1 instanceof Array); //打印结果:true。 + console.log(typeof arr1); //打印结果:object。提示:typeof 方法无法判断是否为数组 +``` + +上方代码表明,只能通过 instanceof 来判断是否为数组。而 typeof 的打印结果是 object。 + + +### 题目二:写一个原型链继承的例子 + +来看个基础的代码: + +20180306_1931.png + + +上面这个例子是基础,但是,在回答面试官的问题时,不要写上面的例子。要写成下面这个例子:(更贴近实战) + + +**举例:**写一个封装DOM查询的例子 + +> 这个例子有点像 jQuery 操作DOM节点。 + +表示这个例子,略难。 + + +### 题目三:描述 new 一个对象的过程 + +(1)创建一个新对象 + +(2)this 指向这个新对象 + +(3)执行代码(对this 赋值) + +(4)返回this + + + + +参考链接: + +- [原型、原型链、继承模式](https://my.oschina.net/u/2600761/blog/1524617) + + + + + + + + +```javascript + +``` \ No newline at end of file diff --git a/06-前端基础/01-页面布局.md b/06-前端基础/01-页面布局.md index bf6daa7..e8f3c2d 100644 --- a/06-前端基础/01-页面布局.md +++ b/06-前端基础/01-页面布局.md @@ -43,7 +43,7 @@ 问题:假设高度默认100px ,请写出三栏布局,其中左栏、右栏各为300px,中间自适应。 -20180305_1520.png +![](http://img.smyhvae.com/20180305_1520.png) 分析: @@ -206,7 +206,7 @@ 效果如下: -20180305_1640.gif +![](http://img.smyhvae.com/20180305_1640.gif) ### 方法3、flexbox布局 @@ -280,7 +280,7 @@ 效果如下: -20180305_1700.gif +![](http://img.smyhvae.com/20180305_1700.gif) @@ -358,7 +358,7 @@ ``` -20180305_1855.gif +![](http://img.smyhvae.com/20180305_1855.gif) ### 方法5、网格布局 grid @@ -424,8 +424,7 @@ 效果: -20180305_1920.gif - +![](http://img.smyhvae.com/20180305_1920.gif) ### 延伸:五种方法的对比 @@ -485,7 +484,7 @@ PS:面试提到网格布局,说明我们对新技术是有追求的。 ### 页面布局的变通 -20180305_1931.png +![](http://img.smyhvae.com/20180305_1931.png) `上下高度固定,中间自适应`,这个在移动端的页面中很常见。 diff --git a/06-前端基础/03-DOM事件的总结.md b/06-前端基础/03-DOM事件的总结.md index 1bacf6b..d2cc808 100644 --- a/06-前端基础/03-DOM事件的总结.md +++ b/06-前端基础/03-DOM事件的总结.md @@ -114,10 +114,9 @@ DOM事件流讲的就是:浏览器在于当前页面做交互时,这个事 - (3)冒泡:从**目标元素**传到 Window 对象。 -![](http://img.smyhvae.com/20180204_1028.gif) +![](http://img.smyhvae.com/20180306_1058.png) - -20180306_1058.png +![](http://img.smyhvae.com/20180204_1218.jpg) ## 描述DOM事件捕获的具体流程 @@ -127,7 +126,7 @@ DOM事件流讲的就是:浏览器在于当前页面做交互时,这个事 ### 捕获的流程 -20180306_1103.png +![](http://img.smyhvae.com/20180306_1103.png) **说明**:捕获阶段,事件依次传递的顺序是:window --> document --> html--> body --> 父元素、子元素、目标元素。 diff --git a/06-前端基础/04-HTTP协议.md b/06-前端基础/04-HTTP协议.md index 017eb6c..1d79763 100644 --- a/06-前端基础/04-HTTP协议.md +++ b/06-前端基础/04-HTTP协议.md @@ -67,7 +67,7 @@ http协议的头部有一个`数据类型`,通过http协议,就可以完成 ## HTTP报文的组成部分 -20180306_1400.png +![](http://img.smyhvae.com/20180306_1400.png) 在回答此问题时,我们要按照顺序回答: @@ -79,7 +79,7 @@ http协议的头部有一个`数据类型`,通过http协议,就可以完成 ### 请求报文包括: -20180228_1505.jpg +![](http://img.smyhvae.com/20180228_1505.jpg) - 请求行:包括请求方法、请求的url、http协议及版本。 @@ -91,7 +91,7 @@ http协议的头部有一个`数据类型`,通过http协议,就可以完成 ### 响应报文包括: -20180228_1510.jpg +![](http://img.smyhvae.com/20180228_1510.jpg) - 状态行:http协议及版本、状态码及状态描述。 @@ -128,7 +128,7 @@ head 可能偶尔用的到。 ## get 和 post的区别 -20180306_1415.png +![](http://img.smyhvae.com/20180306_1415.png) 区别有很多,如果记不住,面试时,至少要任意答出其中的三四条。 @@ -151,11 +151,11 @@ head 可能偶尔用的到。 http状态码分类: -20180306_1430.png +![](http://img.smyhvae.com/20180306_1430.png) 常见的http状态码: -20180306_1431.png +![](http://img.smyhvae.com/20180306_1431.png) 部分解释: @@ -170,7 +170,7 @@ http状态码分类: - 304:我这个服务器告诉客户端,你已经有缓存了,不需要从我这里取了。 -20180306_1440.png +![](http://img.smyhvae.com/20180306_1440.png) 400和401用的不多。403指的是请求被拒绝。404指的是资源不存在。 @@ -209,7 +209,6 @@ http状态码分类: 管线化就是,我把现在的请求打包,一次性发过去,你也给我一次响应回来。 - ### 管线化的注意事项 diff --git a/06-前端基础/05-原型链.md b/06-前端基础/05-原型链.md index e8d4586..90b544f 100644 --- a/06-前端基础/05-原型链.md +++ b/06-前端基础/05-原型链.md @@ -2,6 +2,17 @@ ## 前言 +### 面向对象的三大特性 + +- 封装 + +- 继承 + +- 多态 + +### 原型链的知识 + + 原型链是面向对象的基础,是非常重要的部分。有以下几种知识: - 创建对象有几种方法 @@ -14,4 +25,211 @@ +## 创建对象有几种方法 + +### 方式一:字面量 + +```javascript + var obj11 = {name: 'smyh'}; + var obj12 = new Object(name: `smyh`); +``` + +上面的两种写法是一样的。因为,第一种写法,`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); +``` + +第三种方法,很少有人能说出来。 + + +## 原型、构造函数、实例,以及原型链 + + + + +20180306_1538.png + + + +PS:任何一个函数,如果在前面加了new,那就是构造函数。 + + +### 原型、构造函数、实例三者之间的关系 + + +20180306_2107.png + +- 1、构造函数通过 new 生成实例 + +- 2、构造函数也是函数,构造函数的`prototype`指向原型。(所有的函数有`prototype`属性,但实例没有 `prototype`属性) + +- 3、原型对象中有 constructor,指向该原型的构造函数。 + +上面的三行,代码演示: + +``` + var Foo = function (name) { + this.name = name; + } + + var fn = new Foo('smyhvae'); +``` + +上面的代码中,`Foo.prototype.constructor === Foo`的结果是`true`: + +20180306_2120.png + + +- 4、实例的`_proto_`指向原型。也就是说,`Foo._proto_ === M.prototype`。 + +声明:所有的**引用类型**(数组、对象、函数)都有`_proto_`这个属性。 + +`Foo._proto_ === Function.prototype`的结果为true,说明Foo这个普通的函数,是Function构造函数的一个实例。 + + + + + +### 原型链 + +**原型链的基本原理**:任何一个**实例**,通过原型链,找到它上面的**原型**,该原型对象中的方法和属性,可以被所有的原型实例共享。 + + +Object是原型链的顶端。 + +原型可以起到继承的作用。原型里的方法都可以被不同的实例共享: + +``` + //给Foo的原型添加 say 函数 + Foo.prototype.say = function () { + console.log(''); + } +``` + +**原型链的关键**:在访问一个实例的时候,如果实例本身没找到此方法或属性,就往原型上找。如果还是找不到,继续往上一级的原型上找。 + + +## `instanceof`的原理 + +20180306_2209.png + + +`instanceof`的**作用**:用于判断**引用类型**属于哪个**构造函数**。 + +`instanceof`的**原理**:判断实例对象的`_proto_`属性,和构造函数的`prototype`属性,是否指向同一个地址。 + +**注意**: + +(1)虽然说,实例是由构造函数 new 出来的,但是实例的`_proto_`属性引用的是构造函数的`prototype`。实例的`_proto_`属性与构造函数本身无关。 + + +(2)原型的上面可能还有原型,以此类推往上走。这条链上, instanceof 的返回结果也是 true。 + +```javascript + + + + + +``` + + + + + + + + + +```javascript + + + + + +``` + + + + + + + + + +```javascript + + + + + +``` + + + + + + + + + +```javascript + + + + + +``` + + + + + + + + + +```javascript + + + + + +``` + + + + + + + + + +```javascript + + + + + +``` + + + + +