Git Product home page Git Product logo

my-blog's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

my-blog's Issues

跨域

script、image、iframe的src都不受同源策略的影响。

  1. JSONP,回调函数+数据就是 JSON With Padding,简单、易部署。(做法:动态插入script标签,设置其src属性指向提供JSONP服务的URL地址,查询字符串中加入 callback 指定回调函数,返回的 JSON 被包裹在回调函数中以字符串的形式被返回,需将script标签插入body底部)。缺点是只支持GET,不支持POST(原因是通过地址栏传参所以只能使用GET)

  2. document.domain 跨子域 ( 例如a.qq.com嵌套一个b.qq.com的iframe ,如果a.qq.com设置document.domain为qq.com 。b.qq.com设置document.domain为qq.com, 那么他俩就能互相通信了,不受跨域限制了。 注意:只能跨子域)

  3. window.name + iframe ==> http://www.tuicool.com/articles/viMFbqV,支持跨主域。不支持POST

  4. HTML5的postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。适用于不同窗口iframe之间的跨域

  5. CORS(Cross Origin Resource Share)对方服务端设置响应头

  6. 服务端代理 在浏览器客户端不能跨域访问,而服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就没有跨越问题。简单地说,就是浏览器不能跨域,后台服务器可以跨域。(一种是通过http-proxy-middleware插件设置后端代理;另一种是通过使用http模块发出请求)

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。

专题6: 设计模式之享元模式

模式定义

享元模式,运用共享技术,有效地支持大量的细粒度的对象,以避免对象之间拥有相同内容而造成多余的性能开销。

享元(flyweight)模式的主要作用:性能优化,当系统创建过多相似的对象而导致内存占用过高,可以采用这种设计模式进行优化。

享元模式将对象的属性区分为内部状态与外部状态,内部状态在创建的时候赋值,外部状态在实际需要用到的时候进行动态赋值

对于内部状态和外部状态的区分,有几点:

  1. 内部状态存储于对象内部
  2. 内部状态可以被一些对象共享
  3. 内部状态独立于具体场景,通常不会改变
  4. 外部状态取决于具体场景,并根据场景变化,外部状态不能被共享。

实战

我们要创建 100 个大小相同颜色不同的 div。

不使用享元模式的做法是:

  1. 创建一个创建 div 的类,CreateDiv。
  2. new CreateDiv() 创建 div
  3. 我们需要 new 100 次。这样就造成了很大的空间浪费。
interface Div {
  width: number;
  height: number;
  color: string;
}
const divStore: Div[] = [];

class CreateDiv {
  public width = 100;
  public height = 100;
  public color = this.randomColor()
  // 随机颜色
  private randomColor () {
    const color = ['red', 'green', 'blue', 'white', 'black'];
    return color[Math.floor(Math.random() * color.length)];
  }
}

let count = 100;
while (count--) {
  const innerDiv = new CreateDiv();
  divStore.push(innerDiv);
}

const sizeof = require('object-sizeof')

console.log(sizeof(divStore)) // 5688

享元模式来做

// 将 div 属性设置成内部跟外部两部分
interface Div {
  outer: {
    width: number;
    height: number;
  };
  innter: {
    color: string;
  };
}
// 用来储存 Div
const divStore: Div[] = [];
// 创建外部 div 类
class CreateOuterDiv {
  width: number = 100;
  height: number = 100;
}
class CreateInnerDiv {
  public color = this.randomColor()
  // 随机颜色
  private randomColor () {
    const color = ['red', 'green', 'blue', 'white', 'black'];
    return color[Math.floor(Math.random() * color.length)];
  }
}
// 创建外部 div
const outerDiv = new CreateOuterDiv();
let innerDiv: number;
let count = 100;

while (count--) {
  // 创建内部 div
  innerDiv = new CreateInnerDiv();
  divStore.push({
    outer: outerDiv,
    innter: innerDiv
  });
}

const sizeof = require('object-sizeof')
// 因为这个方法会把引用的对象也全部算一遍,所以我们拆开来算

// 验证:100 * (innerDiv + outerDiv)= 5400 与上面算的 5688 很接近,可以认为这个方法是准确的
console.log(100 * (sizeof(innerDiv) + sizeof(outerDiv))) // 5400
// 100 * innerDiv + outerDiv = 1638
console.log(100 * sizeof(innerDiv) + sizeof(outerDiv)) // 1638

从上面的计算结果来看减少了很大的内存,因为 divStore 数组对象中 outerDiv 其实只有一个,都是它的引用而已。我们的内存占用是 100 * innerDiv + outerDiv,而不使用享元模式的空间是 100 * (innerDiv + outerDiv)

什么是原型链

当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找,如果prototype没有,就会去prototype关联的前辈prototype那里寻找,如果再没有则继续查找Prototype.Prototype引用的对象,依次类推,直到Prototype.….Prototype为undefined(Object的Prototype就是undefined)从而形成了所谓的“原型链”。
其中foo是Function对象的实例。而Function的原型对象同时又是Object的实例。这样就构成了一条原型链。

instanceof 确定原型和实例之间的关系

用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上

对象的__proto__指向自己构造函数的prototype。obj.proto.proto...的原型链由此产生,包括我们的操作符instanceof正是通过探测obj.proto.proto... === Constructor.prototype来验证obj是否是Constructor的实例。

function C(){}
var o = new C(){}
//true 因为Object.getPrototypeOf(o) === C.prototype
o instanceof C

instanceof只能用来判断对象和函数,不能用来判断字符串和数字

isPrototypeOf

用于测试一个对象是否存在于另一个对象的原型链上。
判断父级对象 可检查整个原型链

CDN工作原理

CDN做了两件事,一是让用户访问最近的节点,二是从缓存或者源站获取资源

CDN的工作原理:通过dns服务器来实现优质节点的选择,通过缓存来减少源站的压力。

前端路由实现方式

两种实现前端路由的方式

HTML5 History两个新增的API:history.pushState 和 history.replaceState,两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新。

Hash就是url 中看到 # ,我们需要一个根据监听哈希变化触发的事件( hashchange) 事件。我们用 window.location 处理哈希的改变时不会重新渲染页面,而是当作新页面加到历史记录中,这样我们跳转页面就可以在 hashchange 事件中注册 ajax 从而改变页面内容。 可以为hash的改变添加监听事件:

window.addEventListener("hashchange", funcRef, false)

优点

从性能和用户体验的层面来比较的话,后端路由每次访问一个新页面的时候都要向服务器发送请求,然后服务器再响应请求,这个过程肯定会有延迟。而前端路由在访问一个新页面的时候仅仅是变换了一下路径而已,没有了网络延迟,对于用户体验来说会有相当大的提升。
前端路由的优点有很多,比如页面持久性,像大部分音乐网站,你都可以在播放歌曲的同时,跳转到别的页面而音乐没有中断,再比如前后端彻底分离。 开发一个前端路由,主要考虑到页面的可插拔、页面的生命周期、内存管理等。

缺点

使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存。
History interface提供了两个新的方法:pushState(), replaceState()使得我们可以对浏览器历史记录栈进行修改:

window.history.pushState(stateObject, title, URL)
window.history.replaceState(stateObject, title, URL)

专题1: setInterval有什么弊端

今日专题:setInterval有什么弊端?

这个题目有很多人懂,但是又很多人不懂,这个专题就是让你彻底弄透 setInterval

new操作符具体做了什么

  1. 创建一个空对象,并且this变量引用该对象,同时继承了该函数的原型(实例对象通过__proto__属性指向原型对象;obj.proto = Base.prototype;)

  2. 属性和方法被加入到 this 引用的对象中。

事件委托

因为事件具有冒泡机制,因此我们可以利用冒泡的原理,把事件加到父级上,触发执行效果。这样做的好处当然就是提高性能了

专题4: 设计模式之工厂模式

工厂模式

目的

定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行

使用场景

我们明确地计划不同条件下创建不同实例时

优缺点

优点

  1. 隐藏了对象创建的细节,将产品的实例化过程放到了工厂中实现。
  2. 客户端基本不用关心使用的是哪个产品,只需要知道用工厂的那个方法(或传入什么参数)就行了.
  3. 方便添加新的产品子类,每次只需要修改工厂类传递的类型值就行了。
  4. 遵循了依赖倒转原则。

缺点

  1. 适用于产品子类型差不多, 使用的方法名都相同的情况.
  2. 每添加一个产品子类,都必须在工厂类中添加一个判断分支(或一个方法),这违背了OCP(开闭原则)。

实现

比如我要有一个 Animal 工厂,这个工厂要生产动物。那么我要定义动物都有 Feature特征必须要有 color 颜色跟 bark 叫声。

1. 接口实现

// 定义工厂需要的动物特征
interface Feature {
  color: string;
  bark(): void;
}

// 定义动物类型名字
type name = 'cat' | 'dog'

// 子类必须要实现 Feature 接口的方法
// 这样我们就可以创建白色叫声喵喵喵的猫了
class Cat implements Feature {
  color = "白色";
  bark() {
    console.log(`${this.color} 喵喵喵`);
  }
}
// 创建 Dog 类
class Dog implements Feature {
  color = "黑色";
  bark() {
    console.log(`${this.color} 汪汪汪`);
  }
}
// 这就是一个动物工厂
class Animal {
  createAnimal(type: name) {
    switch (type) {
      case 'cat':
        return new Cat();
      case 'dog':
        return new Dog();
    }
  }
}

const animal = new Animal();
const cat = animal.createAnimal('cat');
const dog = animal.createAnimal('dog');

cat.bark()
dog.bark()

2. 抽象类实现

abstract class Feature {
  abstract color: string;
  abstract bark(): void;
}

// 枚举可以使用的动物类型
enum animalType {
  'cat',
  'dog'
}

// 子类继承抽象类 Feature
// 这样我们就可以创建白色叫声喵喵喵的猫了
class Cat extends Feature {
  color = "白色";
  bark() {
    console.log(`${this.color} 喵喵喵`);
  }
}
// 创建 Dog 类
class Dog extends Feature {
  color = "黑色";
  bark() {
    console.log(`${this.color} 汪汪汪`);
  }
}
// 这就是一个动物工厂
class Animal {
  createAnimal(type: animalType) {
    switch (type) {
      case animalType.dog:
        return new Cat();
      case animalType.dog:
        return new Dog();
    }
  }
}

const animal = new Animal();
const cat = animal.createAnimal(animalType.cat);
const dog = animal.createAnimal(animalType.dog);

cat.bark()
dog.bark()

专题3: 设计模式之单例模式

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

如果我们把代码编程比作是战争的话,那么设计模式就是兵法。不会兵法肯定打不过会兵法的,即使能打过也要付出更多的代价。

设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。

目的:使用设计模式是为了可重用代码,让代码更容易被他人理解、保证代码的可靠性。

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点

特点

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

单例模式场景

  • 电脑上的文件,无论在任何地方修改文件,它都只有一份
  • 古代的皇帝,也只能有一个
  • vue-router 跟 vuex 的 install 也是单例
  • 其实 js 中的子面量对象就是一个天然单例

优缺点

优点

  1. 减少内存开支 单例模式在内存中只有一个实例,减少内存开支,特别是一个对象需要频繁地创建销毁时,而且创建或销毁时性能又无法优化,单例模式就非常明显了
  2. 减少性能开销 由于单例模式只生成一个实例,所以,减少系统的性能开销,当一个对象产生需要比较多的资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。
  3. 避免对资源的多重占用 例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作
  4. 设置全局的访问点 优化和共享资源访问,例如,可以设计一个单例类,负责所有数据表的映射处理。

缺点

  1. 单例很难扩展
  2. 与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

常用的单例模式有两种

  • 懒汉模式
// 懒汉式,只有在调用 getInstance 的时候才会实例化 Singleton
class Singleton {
  static instance = null;
  // 获取实例方法
  static getInstance() {
    return this.instance || (this.instance = new Singleton());
  }
}

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 == instance2); // true
  • 饿汉模式
// 饿汉式,在类初始化的时候就已经创建好了实例
class Singleton {
  static instance = new Singleton();
  // 获取实例方法
  static getInstance() {
    return this.instance;
  }
}

const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 == instance2); // true

http2.0和https

与HTTP/1相比,主要区别包括

  1. HTTP/2采用二进制格式而非文本格式(二进制协议解析起来更高效)

  2. HTTP/2是完全多路复用的,即一个TCP连接上同时跑多个HTTP请求

  3. 使用报头压缩,HTTP/2降低了开销

  4. HTTP/2让服务器可以将响应主动“推送”到客户端缓存中,支持服务端推送(就是服务器可以对一个客户端请求发送多个响应)

HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,TLS/SSL中使用 了非对称加密,对称加密以及HASH算法。比http协议安全。

HTTPS的工作原理

HTTPS 在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息

  1. 什么是keep-alive模式 (持久连接,连接重用)

keep-alive使客户端到服务端的连接持久有效,当出现对服务器的后继请求时,keep-alive功能避免了建立或者重新连接

  1. 不需要重新建立tcp的三次握手,就是说不释放连接

http1.0默认关闭,http1.1默认启用

优点:更高效,性能更高。因为避免了建立/释放连接的开销

  1. http1.0和http1.1区别:
  • 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入更多缓存控制策略,例如Entity tag,If-Match,If-None-Match等

  • Http1.1支持长连接和请求的流水线(pipeline)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,默认开启Connection:keep-alive

专题7: 设计模式之策略模式

定义

定义一系列的算法, 把它们一个个封装起来, 并且使它们可相互替换。

优缺点

优点

  1. 算法可以自由切换。
  2. 避免使用多重条件判断。
  3. 扩展性好,符合开闭原则。

缺点

  1. 策略类会增多。
  2. 所有策略类都需要对外暴露。

实战

在vue中有一个合并选项策略 optionMergeStrategies,它的功能就是把选项添加一些策略,可以达到我们对选项数据操作的目的

官方例子,将选项 _my_option 添加策略,让它的值加一

Vue.config.optionMergeStrategies._my_option = function (parent, child, vm) {
  return child + 1
}

const Profile = Vue.extend({
  _my_option: 1
})

// Profile.options._my_option = 2

我们来简单实现一下这个合并选项策略

// 策略模式 store
const optionMergeStrategies: { [prop: string]: any } = {};

// 给 _my_option 添加策略
optionMergeStrategies._my_option = function(value) {
  return value + 1
}

// 声明 data
const data = {
  // 添加策略
  _my_option: 1,
  // 未添加策略
  option: 1
};

// 响应式
function reactive (data) {
  const hander = {
    get(target, key, value) {
      const v = Reflect.get(target, key, value);
      // 此属性存在策略
      if (typeof optionMergeStrategies[key] === 'function') {
        return optionMergeStrategies[key](v)
      }
      return v
    }
  };
  return new Proxy(data, hander);
}

const proxy = reactive(data);
// 测试是否添加了响应
proxy._my_option = 10
proxy.option = 10

console.log(proxy._my_option, proxy.option); // 11 10

这样你就可以做更多的事情了,比如验证手机号,邮箱等等,再也不用写很多的 if else 了,而且你也可以随时更换策略。符合了设计模式的开闭原则。

缓存,存储相关(cookie,web storage和session)

cookie优点:

  1. 可以解决HTTP无状态的问题,与服务器进行交互 缺点: 1.数量和长度限制,每个域名最多20条,每个cookie长度不能超过4kb 2.安全性问题。容易被人拦截 3.浪费带宽,每次请求新页面,cookie都会被发送过去

cookie和session区别

  1. cookie数据存放在客户的浏览器上,session数据放在服务器上。
  2. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用COOKIE。

sessionStorage是当前对话的缓存,浏览器窗口关闭即消失,localStorage持久存在,除非清除浏览器缓存。

页面缓存原理

页面缓存状态是由http header决定的,一个浏览器请求信息,一个是服务器响应信息。主要包括Pragma: no-cache、Cache-Control、 Expires、 Last-Modified、If-Modified-Since。

js继承方式及其优缺点

  1. 原型链继承的缺点

一是字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。

  1. 借用构造函数(类式继承)

借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起。所以我们需要原型链+借用构造函数的模式,这种模式称为组合继承

  1. 组合式继承

组合式继承是比较常用的一种继承方法,其背后的思路是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。

For detail:https://segmentfault.com/a/1190000002440502

缓存相关

  1. 浏览器输入 url 之后敲下回车,刷新 F5 与强制刷新(Ctrl + F5),又有什么区别?

实际上浏览器输入 url 之后敲下回车就是先看本地 cache-control、expires 的情况,刷新(F5)就是忽略先看本地 cache-control、expires 的情况,带上条件 If-None-Match、If-Modified-Since,强制刷新(Ctrl + F5)就是不带条件的访问。

  1. etag,cache-control,last-modified

如果比较粗的说先后顺序应该是这样:

  1. Cache-Control —— 请求服务器之前
  2. Expires —— 请求服务器之前
  3. If-None-Match (Etag) —— 请求服务器
  4. If-Modified-Since (Last-Modified) —— 请求服务器

需要注意的是 如果同时有 etag 和 last-modified 存在,在发送请求的时候会一次性的发送给服务器,没有优先级,服务器会比较这两个信息.

如果expires和cache-control:max-age同时存在,expires会被cache-control 覆盖。
其中Expires和cache-control属于强缓存,last-modified和etag属于协商缓存 强缓存与协商缓存

区别:强缓存不发请求到服务器,协商缓存会发请求到服务器。

image

专题2: 谈谈你对组件的看法

一个组件应该有以下特征:

  1. 可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的 UI 可以拆分成多个简单的 UI 组件;
  2. 可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个 UI 场景;
  3. 可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;
  4. 可测试(Testable):因为每个组件都是独立的,那么对于各个组件分别测试显然要比对于整个 UI 进行测试容易的多。

开发一个组件需要的考虑

  1. 规范性:是否符合一个常规组件的使用方法,目录、命名、格式是否规范
  2. 质量可靠性:是否经得住长时间考验
  3. 可扩展性:是否可以容易快速扩展新的功能
  4. 兼容性:是否兼容了各个平台
  5. 易用性:是否简单易用,将学习成本降到最低

前端与其他程序开发的共性 高内聚,低耦合,易读写,可复用

  1. 高内聚 是指将在逻辑上可以归类为一个单元的代码封装在一起,尽量保障一块代码集合主要解决一个需求,在前端开发中,最常见的便是将一个逻辑单元的代码使用IIFE函数进行封装。

  2. 低耦合 可以说,保障代码高内聚即在一定程度上满足了代码“低耦合”的要求,因为低耦合即是要求一个逻辑单元的代码块在改动时,不会造成其他逻辑单元代码块的变动,在前端开发中,即是要求各代码块不要过多共享某变量或对象,在不得以的情况下,一定要清晰注释。

  3. 易读写 是指保持代码的可读,可修改性,即在一定时期后,后来的开发者依然可以凭借阅读代码的方式,了解你的编程思路,并根据新的需求,修改你留下的代码。这里牵扯到良好的代码缩进,命名规范,注释等。

  4. 可复用 是指处于节省程序员生命的目的,遵从DRY原则,在一个项目中,抽象出功能类似的业务需求,通过组件化的方式编写代码,实现只写一次,到处使用的令人愉快的目的。

你是如何看待组件的?如果让你写一个组件你会考虑哪些?

说说你对作用域链的理解

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。

专题8: 设计模式之装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

优点

  1. 更好的可读性
  2. 装饰类和被装饰类可以独立发展,不会相互耦合
  3. 装饰模式是继承的一个替代模式
  4. 装饰模式可以动态扩展一个实现类的功能。

缺点

  1. 多层装饰比较复杂。

实战

比如我们要点击一个按钮,但是这个按钮点击时我们想给他加上埋点并做一些登陆的逻辑

我这里使用了 es7 的语法糖,当然不用语法糖也可以做,但是我觉得用的话更简洁一些

// Button 类,内部有一个 click 方法
// 对click方法做了两个修饰
// 一个是添加埋点,一个是登陆
class Button {
  @BuridDecorator
  @LoginDecorator
  click() {
    console.log('点击 dom')
  }
}
// 登陆逻辑的装饰器
function LoginDecorator(target, name, descriptor) {
  const oriFun = target[name]
  descriptor.value = async function() {
    const code = await Login();
    if (code === 0) {
      console.log('登陆成功')
      oriFun.call(this, ...arguments)
    }
  }
}
// 设置埋点的装饰器
function BuridDecorator(target, name, descriptor) {
  console.log(`${name} 方法添加了一个埋点`)
}
// 登陆逻辑
async function Login () {
  return new Promise((resolve, reject)=> {
    setTimeout(() => {
      resolve(0)
    }, 1000)
  })
}
// 点击按钮
const btn = new Button()
btn.click();

// click 方法添加了一个埋点
// 登陆成功
// 点击 dom

说说TCP传输的三次握手四次挥手策略

为了准确无误地把数据送达目标处,TCP协议采用了三次握手策略。用TCP协议把数据包送出去后,TCP不会对传送 后的情况置之不理,它一定会向对方确认是否成功送达。握手过程中使用了TCP的标志:SYN和ACK。

发送端首先发送一个带SYN标志的数据包给对方。接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息。 最后,发送端再回传一个带ACK标志的数据包,代表“握手”结束。 若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。

专题5: 设计模式之适配器模式

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

优缺点

优点

  1. 可以让任何两个没有关联的类一起运行。
  2. 提高了类的复用。
  3. 增加了类的透明度。
  4. 灵活性好。

缺点

  1. 过多地使用适配器,会让系统非常零乱,不易整体进行把握。

实战

举一个例子,你要写一个页面兼容各个端的小程序,那么你就需要根据环境调用不同小程序的 sdk 方法。比如在支付宝中有一个 zhifubaoShare 的分享方法,在微信中有一个 weixinShare 的分享方法。(当然一个sdk还有很多方法,我们只拿分享来举例子)但是我们在工作中其实只希望调用一个 share 方法就能实现不同端的分享。下面我们用适配器模式来做一个 Adapter 适配器。

// =============== 定义接口与类型 ==============================
// 支付宝接口
interface ZhifubaoInerface {
  zhifubaoShare(): void;
}
// 微信接口
interface WeixinInterface {
  weixinShare(): void;
}
// adapter 接口
interface AdapterInterface {
  share(): void;
}
// 合并所有 sdk 类型
interface MergeSdk extends ZhifubaoInerface, WeixinInterface {}
// 支持的平台类型
type platform = 'weixin' | 'zhifubao';


// =============== 代码逻辑实现 ==============================
// 微信 sdk 类实现
class WeixinSdk implements WeixinInterface {
  weixinShare() {
    console.log('微信分享');
  }
}
// 支付宝 sdk 类实现
class ZhifubaoSdk implements ZhifubaoInerface {
  zhifubaoShare() {
    console.log('支付宝分享');
  }
}
// adapter 类实现
class Adapter implements AdapterInterface {
  constructor() {
    this.sdk = this.getPlatfromSdk();
  }
  // 挂载 sdk
  private sdk: MergeSdk;
  // 根据 ua 获取到平台
  private getPlatform(): platform {
    // 默认写了 weixin
    return 'weixin';
  }
  // 将所有 sdk 方法放进一个 map 里
  private getPlatfromSdk() {
    const map = {
      weixin: WeixinSdk,
      zhifubao: ZhifubaoSdk
    };
    const platform = this.getPlatform();
    return new map[platform]() as MergeSdk;
  }
  // 分享功能
  // 实际项目中还有参数的问题,这里为了代码的简洁就不写了
  public share() {
    const platform = this.getPlatform();

    switch (platform) {
      case 'weixin':
        this.sdk.weixinShare();
        break;
      case 'zhifubao':
        this.sdk.zhifubaoShare();
        break;
      default:
        console.log('此方法不存在');
    }
  }
}

const adapter = new Adapter();
// 因为我们默认设置了 weixin 平台
adapter.share(); // 微信分享

双向绑定和单向数据绑定的优缺点

只有 UI控件 才存在双向,非 UI控件 只有单向。 单向绑定的优点是可以带来单向数据流,这样的好处是流动方向可以跟踪,流动单一,没有状态, 这使得单向绑定能够避免状态管理在复杂度上升时产生的各种问题, 程序的调试会变得相对容易。单向数据流更利于状态的维护及优化,更利于组件之间的通信,更利于组件的复用

双向数据流的优点:

无需进行和单向数据绑定的那些CRUD(Create,Retrieve,Update,Delete)操作; 双向绑定在一些需要实时反应用户输入的场合会非常方便 用户在视图上的修改会自动同步到数据模型中去,数据模型中值的变化也会立刻同步到视图中去;

双向数据流的缺点:

双向数据流是自动管理状态的, 但是在实际应用中会有很多不得不手动处理状态变化的逻辑, 使得程序复杂度上升 无法追踪局部状态的变化 双向数据流,值和UI绑定,但由于各种数据相互依赖相互绑定,导致数据问题的源头难以被跟踪到

Vue 虽然通过 v-model 支持双向绑定,但是如果引入了类似redux的vuex,就无法同时使用 v-model。

双绑跟单向绑定之间的差异只在于,双向绑定把数据变更的操作隐藏在框架内部,调用者并不会直接感知。

<input v-model="something">
<!-- 等价于以下内容 -->
<input :value="something" @input="something = $event.target.value">

也就是说,你只需要在组件中声明一个name为value的props,并且通过触发input事件传入一个值,就能修改这个value。

设计模式六大原则

设计模式的六大原则

  1. 开闭原则(Open Close Principle)

开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

  1. 里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

  1. 依赖倒转原则(Dependence Inversion Principle)

这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

  1. 接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计**,它强调降低依赖,降低耦合。

  1. 迪米特法则,又称最少知道原则(Demeter Principle)

最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

  1. 合成复用原则(Composite Reuse Principle)

合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

react和vue的区别

相同点:

  1. 都支持服务端渲染
  2. 都有Virtual DOM,组件化开发,通过props参数进行父子组件数据的传递,都实现webComponents规范
  3. 数据驱动视图
  4. 都有支持native的方案,React的React native,Vue的weex

不同点:

  1. React严格上只针对MVC的view层,Vue则是MVVM模式
  2. virtual DOM 不一样 vue会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树。而对于React而言,每当应用的状态被改变时,全部子组件都会重新渲染。当然,这可以通过shouldComponentUpdate这个生命周期方法来进行控制,
  3. 组件写法不一样 React 推荐的做法是 JSX + inline style,也就是把 HTML 和 CSS 全都写进 JavaScript 了,即”all in js” Vue 推荐的是使用 webpack + vue-loader 的单文件组件格式,即html,css,js写在同一个文件;
  4. 数据绑定:Vue有实现了双向数据绑定,React数据流动是单向的
  5. state对象在react应用中是不可变的,需要使用setState方法更新状态;在Vue中,state对象并不是必须的,数据由data属性在Vue对象中进行管理。

说说你对前端工程化的理解

前端工程化不外乎两点,规范和自动化。
包括 团队开发规范,模块化开发,组件化开发,组件仓库,性能优化,部署,测试,开发流程,开发工具,脚手架,git工作流,团队协作
1.构建工具 2.持续集成 3.系统测试 4.日志统计 5.上线部署 6.敏捷开发 7.性能优化 8.基础框架

代理和反向代理

正向代理: 用浏览器访问时,被残忍的block,于是你可以在国外搭建一台代理服务器,让代理帮我去请求google.com,代理把请求返回的相应结构再返回给我。

反向代理:反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx就是性能非常好的反向代理服务器,用来做负载均衡。 正向代理的对象是客户端,反向代理的对象是服务端

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.