PHP+crontab 完美实现定时任务

PHP由于是顺序执行的脚本语言,多线程编程困难,因此PHP的定时任务相比较JAVA 困难的多,使用Sleep会导致性能极差和系统资源损失,下面我介绍一种高性能,又简单的方式来解决这个问题。

步骤

  1. 编写restful接口,可以用TP这样的框架,或者直接写PHP文件,完成任务逻辑。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    //使用TP框架建立restful接口
    class OauthController extends Controller
    {
    /*
    完成上课提醒
    */
    public function classReminder()
    {
    //查看今天所有课程
    $courses = D("course")->where(array("cday" => date("Y-m-d")))->select();

    foreach ($courses as $course) {
    $cstime = strtotime($course['cstime']);
    $currtime = time();
    $cc = $cstime - $currtime;
    if ($cc < 60 * 60 && $cc > 5 * 60) {
    $ucc = D("user_card_course")->where(array("courseid" => $course["id"]))->select();

    foreach ($ucc as $uc) {
    $re = D("wxmsg")->where(array("userid" => $uc["userid"], "courseid" => $course["id"], "type" => "上课提醒"))->find();
    if ($re) {
    echo "发送过了";
    continue;
    }
    $user = D("oauth_user")->find($uc["userid"]);
    $this->sendTemMsgForClassReminder($user["openid"], $course["id"], $uc["userid"]);
    }
    }
    }
    }
    }
  2. linux添加定时任务,crontab -e 编辑任务

    1
    2
    3
    4
    #每晚2点备份mysql
    0 2 * * * /opt/mysqlBack/bkMysql.sh
    #每15分钟(每小时的 0 15 30 45 分启动),访问接口,并将日志输出到log
    */15 * * * * wget http://localhost/classreminder >/opt/server/gmfitness-schedule/classreminder.log 2>&1
  3. wq!保存。

成功!

Openlayers开发热图

简介:热力图采用PostGis数据库存储地图和人流点数据,通过Geoserver服务发布,前端采用OpenLayers引入并展现完成。

##开发流程图

详细说明

Postgis数据准备

the_geom用于存储坐标信息

企业客户地图:

  • WGS84
  • Postgis 文件
  • monitor库

人流定位数据:

  • 存入Postgis,坐标系:EPSG:4326 该表只存储5分钟内的定位数据,每5分钟刷新一次,并删除之前5分钟的数据
  • 一个企业客户占一个表,一个表里含有多个楼层
  • monitor库
    表示例:
id province_id city_id enterprise building floor the_geom postion_time
1 116 11602 zhongshanyiyuan ZS1 F1 0101000020E6100000000000C0E9D369410000000028F75141 2016-08-08 10:00:00

AP点位数据

存入Postgis,坐标系:EPSG:4326
表示例:
|ft_id|by|fl_id|ft_name_cn|ft_name_en|ft_type|py_type|c_time|u_time|u_flag|the_geom|
|—|
||| ZH0000110100100001| XH1-B1-AP-001||||||| 0101000020E61000001C29C7744A655E405CC51EBF08794340|

新建Geoserver图层

Alt text
Alt text
Alt text

发布WMS服务 style sld

发布地图

Alt text)

发布AP点位

Alt text)

发布人流热图

Alt text)

热图样式设置

一 环境部署
正常部署geoserver,本次版本是2.6
下载地址:http://geoserver.org/release/stable/
另外要下载
Extensions的wps扩展插件。
解压wps,将jar包放进geoserver部署的web-INF/lib中,重启geoserver。

二 生成热力图的样式文件heatmap.sld

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?xml version="1.0" encoding="ISO-8859-1"?>  
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NamedLayer>
<Name>Heatmap</Name>
<UserStyle>
<Title>Heatmap</Title>
<Abstract>A heatmap surface showing population density</Abstract>
<FeatureTypeStyle>
<Transformation>
<ogc:Function name="gs:Heatmap">
<ogc:Function name="parameter">
<ogc:Literal>data</ogc:Literal>
</ogc:Function>
<ogc:Function name="parameter">
<ogc:Literal>weightAttr</ogc:Literal>
<ogc:Literal>jan_je</ogc:Literal>
</ogc:Function>
<ogc:Function name="parameter">
<ogc:Literal>radiusPixels</ogc:Literal>
<ogc:Function name="env">
<ogc:Literal>radius</ogc:Literal>
<ogc:Literal>100</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name="parameter">
<ogc:Literal>pixelsPerCell</ogc:Literal>
<ogc:Literal>10</ogc:Literal>
</ogc:Function>
<ogc:Function name="parameter">
<ogc:Literal>outputBBOX</ogc:Literal>
<ogc:Function name="env">
<ogc:Literal>wms_bbox</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name="parameter">
<ogc:Literal>outputWidth</ogc:Literal>
<ogc:Function name="env">
<ogc:Literal>wms_width</ogc:Literal>
</ogc:Function>
</ogc:Function>
<ogc:Function name="parameter">
<ogc:Literal>outputHeight</ogc:Literal>
<ogc:Function name="env">
<ogc:Literal>wms_height</ogc:Literal>
</ogc:Function>
</ogc:Function>
</ogc:Function>
</Transformation>
<Rule>
<RasterSymbolizer>
<!-- specify geometry attribute to pass validation -->
<Geometry>
<ogc:PropertyName>geom</ogc:PropertyName></Geometry>
<Opacity>0.6</Opacity>
<ColorMap type="ramp" >
<ColorMapEntry color="#0000FF" quantity="0" label="nodata" opacity="0"/>
<ColorMapEntry color="#00FFFF" quantity="0.02" label="nodata"
opacity="0"/>
<ColorMapEntry color="#00FF00" quantity=".1" label="nodata"/>
<ColorMapEntry color="#FFFF00" quantity=".5" label="values" />
<ColorMapEntry color="#FF0000" quantity="1.0" label="values" />
</ColorMap>
</RasterSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>

weightAttr标签指定权重字段,在这里我设置weightAttrz权重字段名称为jan_je。colormap中的热力图符号和范围设置,也是可以改和设置的。
<ogc:PropertyName>geom</ogc:PropertyName></Geometry>这里是指定渲染的图形字段,查看数据库空间数据表的图形字段名称,如果是geom就写geom,如果是the_geom就写the_geom,根据自己数据库中图形字段名称来。在geoserver>style中发布这样的一个sld文件。

Openlayers装载图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 var baseServer = "http://geoserver地址/geoserver/gcks/wms";
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
projection: 'EPSG:900913',
center: [13541202.790897895,4709549.109971935],
zoom: 19
})
});
//人流定位数据图层
var layer1 = new ol.layer.Image({
visible: true,
source: new ol.source.ImageWMS({
ratio: 1,
url: baseServer,
serverType: "geoserver",
params: {
FORMAT: 'image/png',
VERSION: '1.1.0',
LAYERS: 'gcks:mod_heatmap_5mins',
STYLES: ''
}
})
});
//地图数据图层
var layer2 = new ol.layer.Image({
visible: true,
source: new ol.source.ImageWMS({
ratio: 1,
url: baseServer,
serverType: "geoserver",
params: {
FORMAT: 'image/png',
VERSION: '1.1.0',
LAYERS: 'gcks:fl_info_1',
STYLES: ''
}
})
});
map.addLayer(layer1);
map.addLayer(layer2);

最终展示效果:
Alt text)

数据工程师—java京东面试题

京东总部的位置有点捉急,周围荒芜人烟,位于一片农田之中,2016年末,刘强东开始将京东定义为一个技术型驱动的公司,开始打造众多的技术团队,技术氛围不错,但是面试官有些木讷。。。

面试题目

  • 多线程:executor原理 线程池 全解

    • Executor,Executors,ExecutorService,CompletionService,Future,Callable
    • Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
    • public static ExecutorService newFixedThreadPool(int nThreads)
      创建固定数目线程的线程池。
    • public static ExecutorService newCachedThreadPool()
      创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
    • public static ExecutorService newSingleThreadExecutor()
      创建一个单线程化的Executor。
    • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
      创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
    • ExecutorService与生命周期
    • ExecutorService扩展了Executor并添加了一些生命周期管理的方法。
    • 一个Executor的生命周期有三种状态,运行 ,关闭 ,终止 。Executor创建时处于运行状态。当调用ExecutorService.shutdown()后,处于关闭状态,isShutdown()方法返回true。这时,不应该再想Executor中添加任务,所有已添加的任务执行完毕后,Executor处于终止状态,isTerminated()返回true
    • 如果Executor处于关闭状态,往Executor提交任务会抛出unchecked exception RejectedExecutionException
    • 使用CallableFuture返回结果
    • Future<V>代表一个异步执行的操作,通过get()方法可以获得操作的结果,如果异步操作还没有完成,则,get()会使当前线程阻塞。FutureTask<V>实现了Future<V>Runable<V>Callable代表一个有返回值得操作。
    • CompletionService
      在刚在的例子中,getResult()方法的实现过程中,迭代了FutureTask的数组,如果任务还没有完成则当前线程会阻塞,如果我们希望任意字任务完成后就把其结果加到result中,而不用依次等待每个任务完成,可以使CompletionService。生产者submit()执行的任务。使用者take()已完成的任务,并按照完成这些任务的顺序处理它们的结果 。也就是调用CompletionService的take方法是,会返回按完成顺序放回任务的结果,CompletionService内部维护了一个阻塞队列BlockingQueue,如果没有任务完成,take()方法也会阻塞。修改刚才的例子使用CompletionService:
  • hashmap实现原理,hashtable和hashmap区别,为什么hashmap效率高不安全,concurrenthashmap 为什么线程安全,怎样实现的.

在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

HashMap底层就是一个数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。

详细介绍:
hashmap原理全解
hashtable原理全解

  • 手写单例模式示例,单链表倒序排列

    • 单例模式的几种写法:详解点击:单例模式的七种写法
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      //写法一:懒加载,线程不安全
      public class Singleton {
      private static Singleton instance;
      private Singleton (){}

      public static Singleton getInstance() {
      if (instance == null) {
      instance = new Singleton();
      }
      return instance;
      }
      }
      //写法二:懒加载,线程安全
      public class Singleton {
      private static Singleton instance;
      private Singleton (){}
      public static synchronized Singleton getInstance() {
      if (instance == null) {
      instance = new Singleton();
      }
      return instance;
      }
      }
      //写法三:不能懒加载
      public class Singleton {
      private static Singleton instance = new Singleton();
      private Singleton (){}
      public static Singleton getInstance() {
      return instance;
      }
      }
      //写发四:写法三的变种
      public class Singleton {
      private Singleton instance = null;
      static {
      instance = new Singleton();
      }
      private Singleton (){}
      public static Singleton getInstance() {
      return this.instance;
      }
      }
      //写法五:静态内部类
      public class Singleton {
      private static class SingletonHolder {
      private static final Singleton INSTANCE = new Singleton();
      }
      private Singleton (){}
      public static final Singleton getInstance() {
      return SingletonHolder.INSTANCE;
      }
      }
      //写法六:双重校验
      public class Singleton {
      private volatile static Singleton singleton; //保证变量值统一
      private Singleton (){}
      public static Singleton getSingleton() {
      if (singleton == null) {
      synchronized (Singleton.class) {
      if (singleton == null) {
      singleton = new Singleton();
      }
      }
      }
      return singleton;
      }
      }
  • 单链表倒序排列

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    /** 
    * java 实现单链表的逆序
    * @author Administrator
    *
    */
    public class SingleLinkedReverse {

    //定义单链表,每个节点包含数据和下一个节点的地址
    class Node {
    int data;
    Node next;

    public Node(int data) {
    this.data = data;
    }
    }

    public static void main(String[] args) {
    SingleLinkedReverse slr = new SingleLinkedReverse();
    //定义两个链表
    Node head, tail;
    //新建一个链表头结点
    head = tail = slr.new Node(0);
    //新建一个长度为10的链表tail
    for (int i = 1; i < 10; i++) {
    Node p = slr.new Node(i);
    tail.next = p;
    tail = p;
    }
    //tail返回到头节点0 此时head在头结点
    tail = head;
    //循环链表
    while (tail != null) {
    System.out.print(tail.data + " ");
    tail = tail.next;
    }

    head = reverse(head);

    while (head != null) {
    System.out.print(head.data + " ");
    head = head.next;
    }
    }

    /* 核心算法
    前后交换位置
    */
    private static Node reverse(Node head) {
    Node p1, p2 = null;
    p1 = head;

    while (head.next != null) {
    p2 = head.next;
    head.next = p2.next;
    p2.next = p1;
    p1 = p2;
    }
    return p2;
    }
    }
  • 接口和抽象类区别,特点 答案全解

    1. 抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
    2. 抽象类要被子类继承,接口要被类实现。
    3. 接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
    4. 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
    5. 抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
    6. 抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果
    7. 抽象类里可以没有抽象方法
    8. 如果一个类里有抽象方法,那么这个类只能是抽象类
    9. 抽象方法要被实现,所以不能是静态的,也不能是私有的。
    10. 接口可继承接口,并可多继承接口,但类只能单根继承。
  • static 特点 执行顺序

    1. 父类的 static 语句和 static 成员变量

    2. 子类的 static 语句和 static 成员变量

    3. 父类的 非 static 语句块和 非 static 成员变量

    4. 父类的构造方法

    5. 子类的 非 static 语句块和 非 static 成员变量

    6. 子类的构造方法

  • sql的执行顺序SQL Select语句完整的执行顺序: 

    1. from子句组装来自不同数据源的数据;
    2. where子句基于指定的条件对记录行进行筛选;
    3. group by子句将数据划分为多个分组;
    4. 使用聚集函数进行计算;
    5. 使用having子句筛选分组;
    6. 计算所有的表达式;
    7. 使用order by对结果集进行排序。
    8. select 集合输出。
  • having
    在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与合计函数一起使用。

    1
    2
    3
    4
    SELECT Customer,SUM(OrderPrice) FROM Orders
    WHERE Customer='Bush' OR Customer='Adams'
    GROUP BY Customer
    HAVING SUM(OrderPrice)>1500
  • innodb myisam的区别 和原理 答案全解

  • 两种类型最主要的差别就是Innodb 支持事务处理与外键和行级锁。而MyISAM不支持.所以MyISAM往往就容易被人认为只适合在小项目中使用。

  • 作为使用MySQL的用户角度出发,Innodb和MyISAM都是比较喜欢的,如果数据库平台要达到需求:99.9%的稳定性,方便的扩展性和高可用性来说的话,MyISAM绝对是首选。

  • arraylist linkedlist区别
  • 大概的区别
    1. ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
      1. 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
      2. 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
  • ArrayList和LinkedList在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下:
  1. 对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。

  2. 在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。

  3. LinkedList不支持高效的随机元素访问。

  4. ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间

可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了

###10. 基本请求类型

HTTP协议中共定义了八种方法或者叫“动作”来表明对Request-URI指定的资源的 不同操作方式,具体介绍如下:

  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送’*’的请求来测试服务器的功能性。
  • HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
  • GET:向特定的资源发出请求。
  • POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除Request-URI所标识的资源。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。

  • CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。

  • 响应状态码
    全解
    301和302的区别

  • 302重定向是暂时的重定向,搜索引擎会抓取新的内容而保留旧的网址。因为服务器返回302代码,搜索引擎认为新的网址只是暂时的。 SEO 302好于301,但容易被劫持。
  • 301重定向是永久的重定向,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址。不会发生url劫持
  • 微服务什么概念
    微服务是一项在云中部署应用和服务的新技术。大部分围绕微服务的争论都集中在容器或其他技术是否能很好的实施微服务,而红帽说API应该是重点。
    WiKi

chrome web devtool技巧

console

  • copy(x)

    是一个很有用的工具函数方便你将任何东西拷贝到系统的粘贴板暂存。
    给copy函数传入一个没有格式的JSON,会返回格式化的结果。

  • Eager evaluation

    选择该选项可以自动联想你所输入的变量的值,并自动打印出来。

  • debug()

    在执行到某个函数的时候暂停,你可以使用debug函数。debug(fn)接收一个函数作为参数,当每次该函数被调用时,Debugger就会在该函数的第一行中断执行。

  • 暂停UI在Hover状态下的展示结果

    • 打开sources面板
    • 显示tooltip
    • 使用快捷键来暂停脚本执行(将鼠标停留在暂停的图标上查看快捷键 cmd+\ )
    • 回到Elements面板,然后像通常一样去检查元素。

source

通用性面试技巧

面试技巧

形象和谈吐

  • 略正式。
  • 说话幽默,看着对方。
  • 回答问题到细节,避免面试官追问。
  • 要面试官的微信,对于不懂的问题,回去准备发给他。

关键问题

为什么离开公司?

  • 太喜欢你们公司
  • 没有成长空间

自己的缺点?

  • 急性子,为了做事推进,不太估计别人的感受。
  • 对做的事情要求太高,team有时压力会比较大。

自己的优点?

  • 善于学习,高效学习,刻意练习,研究能力。
  • 有韧性。
  • 喜欢研究底层和新的技术,比如go语言。

为什么换工作比较勤?

  • 公司给不了我理想工作环境和状态。
  • 我理想的工作环境和状态。

为什么转前端?

  • 转了以后发现自己做的更好。
  • 学习能力强

你有什么问题?

  • 一线经理还在写代码吗?不懂技术细节怎么带团队。
  • 你觉得你们公司有什么不好的地方吗?
  • 我能帮贵公司做点什么?能不能给我些资料,我先了解下。
  • 面试官对你的评价,指出你的不足和需要改进的地方。

提现自己的能力

  • 死磕某个事
  • 坚持很久的事
  • 逆境不放弃
  • 面对压力,承担责任
  • 严谨细心,对自己做的产品自信
  • 面对诱惑,不浮躁

前端面试题

follow-iu-8_img_885_590.jpg

javascript

  • 有一个全局变量 a,有一个全局函数 b,实现一个方法bindData,执行后,a的任何赋值都会触发b的执行。

    vue简单的双向绑定原理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function bindData(target, event){
    for(var key in target) {
    if(target.hasOwnProperty(key)) {
    (function(){
    var v = target[key];
    Object.defineProperty(target, key, {
    get: function() {
    return v;
    },
    set: function(_value) {
    v = _value;
    event.call(this)
    }
    })
    })()
    }
    }
    }
  • 将数字转换成中文大写的表示,处理到万级别,例如 12345 -> 一万二千三百四十五 CodePen
  • react生命周期 参考答案
  • 闭包
  • v8引擎区别浏览器做的优化
  • 编译型和解释型语言的区别
  • 跟缓存相关的配置
  • 如何提高webpack打包的速度
  • nginx 转发的配置
  • node 的一些特点
  • node对于字节流的控制
  • 如何处理js的错误:eslint。
  • node垃圾回收
  • js内存溢出
  • if([]) 是true,但是[]==false,因为任何类型跟bool比较都会先转化为数值型。[]是object ,if的时候不是false。
  • ()=>{} 箭头函数的区别

    • 更短的语法糖
    • 不绑定this,没有自己的this
    • 没有arguments
    • 不可以作为构造函数,不能用new
    • 没有prototype
  • 实现一个function 输入字符串,验证其字符串是合法的html标签,只要开闭合理就可以。使用栈来解决。

  • setTimeout(function(){},0)和process.nextTick()的区别
  • 红黑树
  • promise,原生写一个
  • 取得body下所有元素的tagname,并去重输出。
  • 前端国际化
  • react组件,如何更换主题
  • setImmediate
  • flex布局 ie10 11不支持
  • css选择器优先级:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Specificity
  • 事件驱动
  • viewport有几种
  • prerender
  • []==[] false 基本数据类型是值的比较,引用类型是地址的比较。
  • proto和prototype

    1
    2
    3
    4
    Object.prototype.__proto__=null  
    Object.__proto__=== Function.prototype
    Function.__proto__===Function.prototype
    Function.__proto__.__proto__=== Object.prototype
  • 事件过程 事件捕获-》目标-》事件冒泡

  • 阻止冒泡方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 阻止冒泡
    stopPropagation() //chrome
    event.cancelBubble() //IE
    // 阻止默认事件
    preventDefault() //chrome
    event.returnValue() //IE

    //JQuery 提供了两种方式来阻止事件冒泡。
    $("#div1").mousedown(function(event){
    event.stopPropagation();
    });
    $("#div1").mousedown(function(event){
    return false;
    });
  • 断点续传,断点下载

  • array的基本方法
  • arguments转化为真正的数组Array.prototype.slice.call(arguments)
  • js数组去重

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //for循环时,每次取出一个元素与对象///进行对比,如果这个元素不重复,则把//它存放到结果数组中,同时把这个元素的内容作为对象的一个属性,并赋值为1,存入到第2步建立的对象中。
    Array.prototype.unique3 = function(){
    var res = [];
    var json = {};
    for(var i = 0; i < this.length; i++){
    if(!json[this[i]]){
    res.push(this[i]);
    json[this[i]] = 1;
    }
    }
    return res;
    }
    var arr = [112,112,34,'你好',112,112,34,'你好','str','str1'];
    alert(arr.unique3());
  • 深拷贝 CodePen

    1
    2
    3
    4
    5
    6
    7
    var clone = function(v) {
    var o = v.constructor === Array ? [] : {};
    for (var i in v) {
    o[i] = typeof v[i] === "Object" ? clone(v[i]) : v[i];
    }
    return o;
    }
  • 闭包

    闭包是指有权访问另一个函数作用域中的变量的函数. 创建闭包常见方式,就是在一个函数内部创建另一个函数.

    • 应用场景 设置私有变量和方法
    • 不适合场景 返回闭包的函数是个非常大的函数
    • 闭包的缺点 常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
  • 为什么会出现闭包这种东西,解决了什么问题

    受JavaScript链式作用域结构的影响,父级变量中无法访问到子级的变量值,为了解决这个问题,才使用闭包这个概念。

  • 交换两个变量的值,但不产生新的变量

    1
    2
    3
    4
    5
    var a=1;
    var b=2;
    a=a+b;
    b=a-b;
    a=a-b;
  • 函数防抖和函数节流

    • 函数防抖 频繁触发的情况下,只有足够的空闲时间,才执行代码一次

      1
      2
      3
      4
      5
      6
      7
      var timer = false
      document.getElementById("debounce").onScroll = function() {
      clearTimeout(timer)
      timer = setTimeout(function(){
      console.log(‘函数防抖’)
      }, 300)
      }
    • 函数节流 声明一个变量当标志位,记录当前代码是否在执行

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      var canScroll = true;
      document.getElementById('throttle').onScroll = function() {
      if (!canScroll) {
      return;
      }
      canScroll = false;
      setTimeout(function(){
      console.log('函数节流');
      canScroll = true;
      },300)
      }
  • js继承
    理解JS的6种继承方式

  • call 和apply
    详解call和apply

  • node延迟函数执行顺序是什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    setTimeout(()=>{
    console.log(3)
    },0);
    setImmediate(()=>{
    console.log(2)
    });
    process.nextTick(()=>{
    console.log(4)
    })

    // 4 2 3

    以上代码的执行顺序为:

    1. process.nextTick
    2. setImmediate
    3. setTimeout
  • 严格模式: “use strict”

  • 数据类型: 6种,Undefined,Null,Boolean,Number,String,Object.注意数据不是哈,数组被归于object
  • 使用typeof操作符,可能返回以下六种结果:undefined,boolean,string,number,object,function.
  • typeof null=object
  • 函数不是一种数据类型。
  • 虽然null==undefined ,但null指的是一个空的对象引用。undefined 表明变量没有被赋值或者未定义。
  • 永远不要测试某个特定的浮点数
  • NaN是一种数值,NaN与任何数都不等,包括他本身。
  • Number() 可以转换任何数据类型,parseInt()和parseFloat()只能字符串转数值
  • Number(true)=1,Number(false)=0,Number(null)=0,Number(“”)=0
  • 其他类型转化为字符串,.toString()方法,String(),区别在于null和undefined没有toSting()方法,必须要用String()
  • 判断一个值是哪种基本类型使用typeof ,是哪种引用类型用instanceof
  • 让js启动变量的回收,var a=121,a=null

JavaScript的新标准

  • await
  • symbol
  • async
  • reflect
  • proxy

webpack

  • webpack babel配置中的stage-0是什么意思?
  • webpack 打包构建速度优化
    • 缩小文件的搜索范围
    • 私用DllPlugin减少基础模块的编译次数
    • 使用happyPack开启多进程Loader转换
    • 使用ParallelUglifyPlugin开启多进程压缩JS 文件
  • webpack 开发体验优化
    • 监听文件修改并自动刷新
    • 开启模块热替换HMR
  • 优化输出质量,减小输出代码体积
    • 区分环境,减小生产环境代码体积
    • 压缩JS ES CSS
    • 使用Tree Shaking 踢出JS死代码
  • 优化输出质量,加速网络请求
    • CDN加速
    • HTTP2
    • 公共代码提取
    • 按需加载
  • 提升代码运行效率
    • 使用Prepack提前求值
    • 使用Scope Hoisting,作用域提升
  • 使用输出分析工具
    • 官方工具Webpack Analyse
    • webpack-bundle-analyzer
  • 其他TIPs
    • use: [‘babel-loader?cacheDirectory’],缓存babel编译结果结果。
    • profile:true 展示webpack构建性能信息
    • cache:true 通过缓存提升构建速度
    • 使用url-loader将小图片用base64加到css或者js中。
    • 通过imagemin-webpack-plugin压缩图片,通过webpack-spritesmith制作雪碧图
    • 开发环境下将devtool设置为cheap-module-eval-source-map,因为生成这种source map的速度最快,能加速构建。在生产环境下将devtool设置为hidden-source-map

模块化

  • AMD requirejs 依赖前置
  • CMD seajs 就近依赖
  • commonjs node
  • ES6模块化:export import

前端安全

  • XSS(跨站脚本攻击)
  • CSRF跨站请求伪造

    伪造成合法用户发起请求。一个网站中有一个a标签href是删除用户信息的url,如果是post可以模拟表单提交。

  • HTTP劫持,
  • 界面操作劫持,
  • 错误的内容推断(使用X-Content-Type-OptionsHTTP:nosniff)
  • 保护cookies httpOnly为true,阻止js调用该cookies属性。

vue

  • vue 更新机制,双向绑定。
  • react 更新机制,diff算法。
  • 事件机制 emit和 on实现。

React

  • React高阶组件

HTML5离线存储和本地缓存

  • 离线存储
  • localStorage 和 sessionStorage方法
    不同域下就算key相同取不到的值也不同,如localhost和127.0.0.1
    1
    2
    3
    4
    localStorage.setItem("key","value")
    localStorage.getItem("key","value")
    localStorage.removeItem("key")
    localStorage.clear()

css

  • 实现图片边框和渐变边框

    1
    border-image:url()   linear-gradient(red, yellow) 10;
  • 多背景设置

    1
    2
    3
    background-image: url(https://mdn.mozillademos.org/files/11305/firefox.png),
    url(https://mdn.mozillademos.org/files/11307/bubbles.png),
    linear-gradient(to right, rgba(30, 75, 115, 1), rgba(255, 255, 255, 0));
  • 文字省略样式:

    1
    2
    3
    text-overflow:ellipsis;
    overflow:hidden;
    white-space:nowrap;
  • 文字波浪下划线

    1
    text-decoration:green wavy underline
  • 清除浮动方法 CodePen

  • 等高布局 CodePen

    • 最完美的解决方式:等高布局有几种不同的方法,但目前为止我认为浏览器兼容最好最简便的应该是padding补偿法。首先把列的padding-bottom设为一个足够大的值,再把列的margin-bottom设一个与前面的padding-bottom的正值相抵消的负值,父容器设置超出隐藏,这样子父容器的高度就还是它里面的列没有设定padding-bottom时的高度,当它里面的任一列高度增加了,则父容器的高度被撑到它里面最高那列的高度,其他比这列矮的列则会用它们的padding-bottom来补偿这部分高度差。因为背景是可以用在padding占用的空间里的,而且边框也是跟随padding变化的,所以就成功的完成了一个障眼法。
  • 盒子模型 box-sizing

    1
    2
    content-box = width (content的宽)
    border-box = width + border + padding
  • 垂直水平居中 CodePen

  • 自适应居中 CodePen
  • css3实现正方形
  • css3新特性(举几个例子)

    • Text-decoration:文字和边界可以填充颜色

      1
      2
      3
      Text-fill-color: 文字内部填充颜色
      Text-stroke-color: 文字边界填充颜色
      Text-stroke-width: 文字边界宽度
    • border-radius和rgba透明度支持

    • Gradient 渐变效果

      1
      background-image:-webkit-gradient(linear,0% 0%,100% 0%,from(#2A8BBE),to(#FE280E));
    • 阴影(Shadow)和反射(Reflect)效果

  • flex布局
  • Transitions, Transforms 和 Animation CodenPen
  • css 预编译
    • less
    • stylus
    • post css
    • css module

正则表达式

  • 写一个简单的模板引擎(字符串和正则)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    var tem="我爱你,${0},${1}"
    var a="小吴"
    var b="小刘"
    function tempFunc(template){
    var reps=template.match(/\${[\d]+}/g)
    for(let i=0;i<reps.length;i++){
    var ar=arguments[i+1]
    if(ar){
    template=template.replace(reps[i],ar)
    }else{
    template=template.replace(reps[i],"")
    }
    }
    return template
    }

    var t=tempFunc(tem,a,b)
  • 12345678.22 转化为 12,345,678.22

    1
    '1234567891'.replace(/(\d+?)(?=(\d{3})+$)/g, '$1,')
  • 12,345,678.20 转化为 12345678.20

    new Number(string.replace(/[^0-9.]/g,''))
    

    网络

  • DNS
    • dig www.baidu.com 可以查看DNS解析过程
    • 域名总长度则不能超过253个字符
    • ICANN 管理 WHOIS 数据库
  • http1和http2区别
    • 新的二进制格式
    • 多路复用
    • header压缩
    • 服务端推送:server push
  • https 的过程和服务器搭建
  • http 的无状态

web 新技术

  • Web Assembly
  • PWA
  • Houdini:自定义css属性
  • web socket
  • service work

项目经验

  • 选择你最引以为傲的项目,细细聊。

linux命令

ab工具

ab -n 1000 -c 100 -v 3 https://mobile.vipkid.com.cn/rest/pd-activity/api/activity/user/activity/getActivityAwardDetailByActivityIdToMobile/47

查看文档神器 man

man

react-devtools 2.1.9版本 免翻墙下载和使用 闪烁解决方案

如果不翻墙的话是不能安装chrome的插件的,因此不能下载react devtools, 网上搜到的都是1.3的版本,那个版本会出现react面板闪烁的情况,下载最新的版本就可以解决问题。

Paste_Image.png

  • 安装直接将crx拖拽到 chrome://extensions/ 里

Paste_Image.png

  • 重启chrome,F12看到react面板

Paste_Image.png

完美搞定!


欢迎访问我的blog: http://yondu.vip

未批恩搭建

用过很多VPN工具,免费的最不靠谱,收费的参差不齐,shadowsocks算是比较成熟而且一直在更新改动。

网站购买

image.png

  • 可以支付宝直接转账付款

下载客户端

https://ss-proxy.info/downloads.php

image.png

有windows,mac, Android ,IOS不同版本,都比较方便

配置

购买之后选择我的服务就能看到四个IP地址:

image.png

  • 日本的vpn一般是最快的,但有些人对欧美的需求更大,但是日本的足够了,唯一不好的就是看YouTube会有日语的广告!!
  • 这些IP是用于配置你的VPN客户端的,现在的客户端提供扫二维码配置的功能非常好用,点击普通图像

image.png
这样就配置成功了,选择某个服务就可以了,当然是要用密码的。

小技巧

VPN分为三种模式:全局,PAC自动模式,手动模式
一般采用PAC自动模式,其原理就是官方持续更新一组域名的白名单库,只有在库里的域名才会走VPN,当然你也可以自己添加域名或者IP。

委托模式

我们再来看 Go 语言这个模式,Go 语言的这个模式挺好玩儿的。声明一个 struct,跟 C 很一样,然后直接把这个 struct 类型放到另一个 struct 里。

委托的简单示例

我们来看几个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Widget struct {  
X, Y int
}

type Label struct {
Widget // Embedding (delegation)
Text string // Aggregation
X int // Override
}

func (label Label) Paint() {
// [0xc4200141e0] -Label.Paint("State")
fmt.Printf("[%p] - Label.Paint(%q)\n", &label, label.Text)
}

上面,

  • 我们声明了一个 Widget,其有 X,Y;
  • 然后用它来声明一个 Label,直接把 Widget 委托进去;
  • 然后再给 Label 声明并实现了一个 Paint() 方法。
    于是,我们就可以这样编程了:
1
2
3
4
5
6
7
8
9
10
label := Label{ Widget{10, 10}, "State", 100 }

// X=100, Y=10, Text=State, Widget.X=10
fmt.Printf("X=%d, Y=%d, Text=%s Widget.X=%d\n",label.X, label.Y, label.Text,label.Widget.X)
fmt.Println()

// {Widget:{X:10 Y:10} Text:State X:100}
// {{10 10} State 100}
fmt.Printf("%+v\n%v\n", label, label)
label.Paint()

我们可以看到,如果有成员变量重名,则需要手动地解决冲突。

我们继续扩展代码。

先来一个 Button:

type Button struct { Label // Embedding (delegation)}func NewButton(x, y int, text string) Button { return Button{Label{Widget{x, y}, text, x}}}func (button Button) Paint() { // Override fmt.Printf(“[%p] - Button.Paint(%q)\n”, &button, button.Text)}func (button Button) Click() { fmt.Printf(“[%p] - Button.Click()\n”, &button)}

再来一个 ListBox:

type ListBox struct { Widget // Embedding (delegation) Texts []string // Aggregation Index int // Aggregation}func (listBox ListBox) Paint() { fmt.Printf(“[%p] - ListBox.Paint(%q)\n”, &listBox, listBox.Texts)}func (listBox ListBox) Click() { fmt.Printf(“[%p] - ListBox.Click()\n”, &listBox)}

然后,声明两个接口用于多态:

type Painter interface { Paint()}type Clicker interface { Click()}

于是我们就可以这样泛型地使用(注意其中的两个 for 循环):

button1 := Button{Label{Widget{10, 70}, “OK”, 10}}button2 := NewButton(50, 70, “Cancel”)listBox := ListBox{Widget{10, 40}, []string{“AL”, “AK”, “AZ”, “AR”}, 0}fmt.Println()//[0xc4200142d0] - Label.Paint(“State”)//[0xc420014300] - ListBox.Paint([“AL” “AK” “AZ” “AR”])//[0xc420014330] - Button.Paint(“OK”)//[0xc420014360] - Button.Paint(“Cancel”)for _, painter := range []Painter{label, listBox, button1, button2} { painter.Paint()}fmt.Println()//[0xc420014450] - ListBox.Click()//[0xc420014480] - Button.Click()//[0xc4200144b0] - Button.Click()for _, widget := range []interface{}{label, listBox, button1, button2} { if clicker, ok := widget.(Clicker); ok { clicker.Click() }}

一个 Undo 的委托重构

上面这个是 Go 语中的委托和接口多态的编程方式,其实是面向对象和原型编程综合的玩法。这个玩法可不可以玩得更有意思呢?这是可以的。

首先,我们先声明一个数据容器,其中有 Add()、 Delete() 和 Contains() 方法。还有一个转字符串的方法。

type IntSet struct { data map[int]bool}func NewIntSet() IntSet { return IntSet{make(map[int]bool)}}func (set IntSet) Add(x int) { set.data[x] = true}func (set IntSet) Delete(x int) { delete(set.data, x)}func (set IntSet) Contains(x int) bool { return set.data[x]}func (set IntSet) String() string { // Satisfies fmt.Stringer interface if len(set.data) == 0 { return “{}” } ints := make([]int, 0, len(set.data)) for i := range set.data { ints = append(ints, i) } sort.Ints(ints) parts := make([]string, 0, len(ints)) for _, i := range ints { parts = append(parts, fmt.Sprint(i)) } return “{“ + strings.Join(parts, “,”) + “}”}

我们如下使用这个数据容器:

ints := NewIntSet()for _, i := range []int{1, 3, 5, 7} { ints.Add(i) fmt.Println(ints)}for _, i := range []int{1, 2, 3, 4, 5, 6, 7} { fmt.Print(i, ints.Contains(i), “ “) ints.Delete(i) fmt.Println(ints)}

这个数据容器平淡无奇,我们想给它加一个 Undo 的功能。我们可以这样来:

type UndoableIntSet struct { // Poor style IntSet // Embedding (delegation) functions []func()}func NewUndoableIntSet() UndoableIntSet { return UndoableIntSet{NewIntSet(), nil}}func (set UndoableIntSet) Add(x int) { // Override if !set.Contains(x) { set.data[x] = true set.functions = append(set.functions, func() { set.Delete(x) }) } else { set.functions = append(set.functions, nil) }}func (set UndoableIntSet) Delete(x int) { // Override if set.Contains(x) { delete(set.data, x) set.functions = append(set.functions, func() { set.Add(x) }) } else { set.functions = append(set.functions, nil) }}func (set *UndoableIntSet) Undo() error { if len(set.functions) == 0 { return errors.New(“No functions to undo”) } index := len(set.functions) - 1 if function := set.functions[index]; function != nil { function() set.functions[index] = nil // Free closure for garbage collection } set.functions = set.functions[:index] return nil}

于是就可以这样使用了:

ints := NewUndoableIntSet()for _, i := range []int{1, 3, 5, 7} { ints.Add(i) fmt.Println(ints)}for _, i := range []int{1, 2, 3, 4, 5, 6, 7} { fmt.Println(i, ints.Contains(i), “ “) ints.Delete(i) fmt.Println(ints)}fmt.Println()for { if err := ints.Undo(); err != nil { break } fmt.Println(ints)}

但是,需要注意的是,我们用了一个新的 UndoableIntSet 几乎重写了所有的 IntSet 和 “写” 相关的方法,这样就可以把操作记录下来,然后 Undo 了。

但是,可能别的类也需要 Undo 的功能,我是不是要重写所有的需要这个功能的类啊?这样的代码类似,就是因为数据容器不一样,我就要去重写它们,这太二了。

我们能不能利用前面学到的泛型编程、函数式编程、IoC 等范式来把这个事干得好一些呢?当然是可以的。

如下所示:
● 我们先声明一个 Undo[] 的函数数组(其实是一个栈)。
● 并实现一个通用 Add()。其需要一个函数指针,并把这个函数指针存放到 Undo[] 函数数组中。
● 在 Undo() 的函数中,我们会遍历Undo[]函数数组,并执行之,执行完后就弹栈。
type Undo []func()func (undo Undo) Add(function func()) { undo = append(undo, function)}func (undo Undo) Undo() error { functions := undo if len(functions) == 0 { return errors.New(“No functions to undo”) } index := len(functions) - 1 if function := functions[index]; function != nil { function() functions[index] = nil // Free closure for garbage collection } undo = functions[:index] return nil}

那么我们的 IntSet 就可以改写成如下的形式:

type IntSet struct { data map[int]bool undo Undo}func NewIntSet() IntSet { return IntSet{data: make(map[int]bool)}}

算法练级

Two Sum algorithm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* twoSum indexOf 方法
*/
var twoSum = function(nums, target) {
for (let i=0;i<nums.length;i++){
var index = nums.indexOf(target-nums[i])
if (index>-1 && index!=i){
return [i,index]
}
}
return []
};

/*
* hash algorithm
*/
var twoSum = function(nums, target) {
var map={}
for (let i=0;i<nums.length;i++){
if (map.hasOwnProperty(target-nums[i])){
return [map[target-nums[i]],i]
}
map[nums[i]]=i
}
return []
};
/*
* two point algorithm
*/
var twoSum = function(nums, target) {
var l=0,r=nums.length-1, newNums=nums.concat()
//At first, sorting.
newNums.sort((a,b)=>a-b)
while(l!=r){
var m = newNums[l] + newNums[r] - target
if (m < 0){
l++
}else{
if(m==0){
// lastIndexOf for solving : [3,3] and 6 is [0,1]
return [nums.indexOf(newNums[l]),nums.lastIndexOf(newNums[r])]
}
r--
}
}
return []
}
var re=twoSum([2,11,7,7],9)
console.log(re)

代码规范

  • 二元运算符左右两边加空格
    • if, for 和括号之间加空格
    • 严格按照要求进行程序缩进
      即使 if / for
    • 语句内部只有一句话,也要加上花括号
    • 变量名使用有意义的英文名,不要用a,b,c,s1,s2
    • 区分不同的逻辑块,逻辑块之间用空行隔开,简要注释每个部分做的事情
    • 多用 Helper Function 或子函数,不要所有程序都写在一个大函数里

Chrome 63的新功能

全新google chrome 发展到了63版本,从 google developers 的官网获悉该版本增加了很多新的功能。

  • 允许动态引入JavaScript modules
  • 更简单的异步迭代器
  • 可以通过css的overscroll-behavior属性改变浏览器scroll的默认行为
    setTimeout(()=>{console.log(3)},0);setImmediate(()=>{console.log(2)});process.nextTick(()=>{console.log(4)})

编程范式:逻辑编程

这篇文章重点介绍 Prolog 语言。Prolog(Programming in Logic 的缩写)是一种逻辑编程语言。它创建在逻辑学的理论基础之上,最初被运用于自然语言等研究领域。现在它已被广泛地应用在人工智能的研究中,可以用来建造专家系统、自然语言理解、智能知识库等。

Prolog 语言最早由艾克斯马赛大学(Aix-Marseille University)的 Alain Colmerauer 与 Philippe Roussel 等人于 20 年代 60 年代末研究开发的。1972 年被公认为是 Prolog 语言正式诞生的年份,自 1972 年以后,分支出多种 Prolog 的方言。

最主要的两种方言为 Edinburgh 和 Aix-Marseille。最早的 Prolog 解释器由 Roussel 建造,而第一个 Prolog 编译器则是 David Warren 编写的。

Prolog 一直在北美和欧洲被广泛使用。日本政府曾经为了建造智能计算机而用 Prolog 来开发 ICOT 第五代计算机系统。在早期的机器智能研究领域,Prolog 曾经是主要的开发工具。

20 世纪 80 年代 Borland 开发的 Turbo Prolog,进一步普及了 Prolog 的使用。1995 年确定了 ISO Prolog 标准。

有别于一般的函数式语言,Prolog 的程序是基于谓词逻辑的理论。最基本的写法是定立对象与对象之间的关系,之后可以用询问目标的方式来查询各种对象之间的关系。系统会自动进行匹配及回溯,找出所询问的答案。

Prolog 代码中以大写字母开头的元素是变量,字符串、数字或以小写字母开头的元素是常量。下划线(_)被称为匿名变量。

Prolog 的语言特征

逻辑编程是靠推理,比如下面的示例:

program mortal(X) :- philosopher(X).philosopher(Socrates).philosopher(Plato).philosopher(Aristotle).mortal_report:-write(‘Known mortals are:’), nl, mortal(X),write(X),nl,fail.

我们可以看到下面的几个步骤。
  1. 先定义一个规则:哲学家是人类。
  2. 然后陈述事实:苏格拉底、亚里士多德、柏拉图都是哲学家。
  3. 然后,我们问,谁是人类?于是就会输出苏格拉底、亚里士多德、柏拉图。
下面是逻辑编程范式的几个特征。
  • 逻辑编程的要点是将正规的逻辑风格带入计算机程序设计之中。
  • 逻辑编程建立了描述一个问题里的世界的逻辑模型。
  • 逻辑编程的目标是对它的模型建立新的陈述。
    • 通过陈述事实——因果关系。
    • 程序自动推导出相关的逻辑。
经典问题:地图着色问题

我们再来看一个经典的四色地图问题。任何一个地图,相同区域不能用相同颜色,只要用四种不同的颜色就够了。
首先,定义四种颜色。

color(red).color(green).color(blue).color(yellow).

然后,定义一个规则:相邻的两个地区不能用相同的颜色。

neighbor(StateAColor, StateBColor) :- color(StateAColor), color(StateBColor),     StateAColor \= StateBColor. / \= is the not equal operator /

最前面的两个条件:color(StateAColor) 和 color(StateBColor) 表明了两个变量 StateAColor 和 StateBColor。然后,第三个条件: StateAColor \= StateBColor 表示颜色不能相同。

接下来的事就比较简单了。我们描述事实就好了,描述哪些区域是相邻的事实。

比如,下面描述了 BW 和 BY 是相邻的。

germany(BW, BY) :- neighbor(BW, BY).

下面则描述多个区 BW、 BY、 SL、 RP、 和 ND 的相邻关系:

germany(BW, BY, SL, RP, HE) :- neighbor(BW, BY), neighbor(BW, RP), neighbor(BW, HE).

于是,我们就可以描述整个德国地图的相邻关系了。

germany(SH, MV, HH, HB, NI, ST, BE, BB, SN, NW, HE, TH, RP, SL, BW, BY) :- neighbor(SH, NI), neighbor(SH, HH), neighbor(SH, MV),neighbor(HH, NI),neighbor(MV, NI), neighbor(MV, BB),neighbor(NI, HB), neighbor(NI, BB), neighbor(NI, ST), neighbor(NI, TH),neighbor(NI, HE), neighbor(NI, NW),neighbor(ST, BB), neighbor(ST, SN), neighbor(ST, TH),neighbor(BB, BE), neighbor(BB, SN),neighbor(NW, HE), neighbor(NW, RP),neighbor(SN, TH), neighbor(SN, BY),neighbor(RP, SL), neighbor(RP, HE), neighbor(RP, BW),neighbor(HE, BW), neighbor(HE, TH), neighbor(HE, BY),neighbor(TH, BY),neighbor(BW, BY).

最后,我们使用如下语句,就可以让 Prolog 推导到各个地区的颜色。

?- germany(SH, MV, HH, HB, NI, ST, BE, BB, SN, NW, HE, TH, RP, SL, BW, BY).

小结

Prolog 这种逻辑编程,把业务逻辑或是说算法抽象成只关心规则、事实和问题的推导这样的标准方式,不需要关心程序控制,也不需要关心具体的实现算法。只需要给出可以用于推导的规则和相关的事实,问题就可以被通过逻辑推导来解决掉。是不是很有意思,也很好玩?

如果有兴趣,你可以学习一下,这里推荐两个学习资源:

在php类里,对象数组按照属性排序,usort的使用

usort, create_function

该问题主要使用的是 create_function() 方法


class Test{
 public  function s(){
  $res=arry()
  array_push($res,array('id'=>2))
  array_push($res,array('id'=>1))

  $cmp_func = create_function('$a,$b', '
    if($a["id"]  ==  $b["id"])  return  0;
    return  $a["id"]>$b["id"]?-1:1;');
        // 对结果排序 保证目录在前面
  usort($res, $cmp_func);
    }
}

基于webpack 的 vue 多页架构

使用vue构建单页应用已经是稀松平常的事情了,但是当你遇到类似活动类需求时,每个活动相对独立,当活动达到30各以上时,长时间的构建过程会拖慢整个开发周期,而且也是不必要的。因此多页架构应运而生。

脚手架

github地址:`git@github.com:lihongbin100/any-page-demo.git`

目录结构

page下包含多个目录,每个目录对应一个项目,都要包含main.js入口文件和app.vue主组件。

配置说明

多页架构最重要的就是webpack的多target配置,webpack的配置可以接收一个配置数组,从而一次性对多个项目分别打包。

  • 但是如何配置需要打包哪个项目呢?

package.json文件里有pages参数,该参数可以配置page目录下的任意一个或者多个项目,配置了哪个项目,就会打包哪个项目,注意项目名称要跟目录名相同,这样不论是上线,还是本地开发,都不需要整个项目部署,而是用到哪个就打包哪个。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"name": "any-page-demo",
"version": "1.0.0",
"description": "多页面架构demo",
"main": "app.js",
"pages": "page1,page2",
"scripts": {
"update": "npm --registry=https://registry.npm.taobao.org install -E --unsafe-perm",
"init": "npm --registry=https://registry.npm.taobao.org install -E --unsafe-perm",
"release": "npm run clean && webpack --env=prod",
"test": "rm -rf ./dist && webpack --env=test",
"dev": "export NODE_ENV=development && node app.js",
"clean": "rm -rf ./output",
"lint": "eslint --fix 'src/**/*.vue' 'src/**/*.js'"
},
"pre-commit": [
"lint"
],
------省略
}

  • 打包的核心在于webpack.config.js中配置。最重要的就是下面生成webpack的配置数组。
    1
    2
    3
    4
    5
    process.env.npm_package_pages.split(",").forEach(
    (page) => {
    configs.push(merge(common(page), currentConfig(page)))
    }
    )

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const merge = require('webpack-merge')
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var common = (page) => {
return {
entry: {
vendor: [
'vue',
'cookies-js',
'form-urlencoded',
],
main: `src/page/${page}/main.js`
},
-------省略
}

module.exports = function (env) {
let currentConfig = {}
if (env == "dev") {
currentConfig = devConfig
}
if (env == "test") {
currentConfig = testConfig
}
if (env == "prod") {
currentConfig = propConfig
}
const configs = [] //重点在这
process.env.npm_package_pages.split(",").forEach(
(page) => {
configs.push(merge(common(page), currentConfig(page)))
}
)
return configs
}

前端开发-家里蹲工作环境搭建

以MAC为例!

必备软件工具:

1. VPN软件:每个公司都有会有自己的vpn吧,如果没有那就自己搭建一个,建议使用shadowscoks。

2. host:相信开发过程中要配置很多测试环境的host,推荐使用SwitchHosts。

其实有VPN基本上,就可以在自己的电脑上开发了,但是有些手机端的页面还是需要用到不同机型的手机来调试的。

那就需要让你的手机连接上你的电脑的网络,这样不只可以共享电脑连接公司网络的VPN还能共享host。

3. mac上使用fiddler比较复杂,但是有一款MAC的专属神器:charles

charles4.2.1 下载地址:https://www.charlesproxy.com/assets/release/4.2.1/charles-proxy-4.2.1.dmg
charles破解jar包:https://www.zzzmode.com/mytools/charles/
输入RegisterName(此名称随意,用于显示 Registered to xxx),选择已安装的版本,点击生成,并下载charles.jar文件
替换本地charles.jar文件
macOS: /Applications/Charles.app/Contents/Java/charles.jar


使用方法:

1. 打开charles ,配置http proxy
2. 设置端口
3.查看电脑的内网IP地址:
MAC命令:ifconfig

4. 保证手机与电脑处于同一局域网内,然后配置手机的代理
打开WIFI设置->选择你连接的WIFI热点->选择代理->手动
5.此时就可以访问了,大功告成!!!
charles还可以查看请求情况,当然https查看不了。


前端架构



前端基础架构包含三部分:
工具 
规范 
系统

工具包含: 测试工具,代码管理(git,npm),代码品质(eslint,csslint),运行监测(console异常,接口异常,性能监测)
库和框架:


————————————————————————
尤雨溪

组件:
- 接入型 container
- 展示型
- 交互型 比如各类加强版的表单组件,通常强调复用
- 功能型 比如 &lt;router-view&gt;&lt;transition&gt;,作为一种扩展、抽象机制存在。

渲染变化侦测机制:
- 命令式(js)
- 声明式(css)
view = render(state)



微信html5进阶之路

概述

我们在微信朋友圈里经常看到很多人分享h5的链接,有的科技感十足,有的展示炫目,有的非常有创意,各大公司也把h5作为他们品牌传播,活动预热的很好方式。企业商户对于这种方式也很有好感,从而导致了h5制作行业涌进大批从业者,同时也成为众多程序员赚取外快的途径。

现在说人话。。。

先来讲讲当前h5行业的现状吧!

h5制作网站

低门槛的h5制作平台,不懂代码的人也可以来玩玩,如果你有一定的设计思维和作图能力,也能做出非常好看的h5作品。

国内比较出名的h5制作网站有:

  • 兔展:设计感和创意感最强的平台,但是制作相对复杂,需要设计基础。
  • 易企秀:老牌的h5制作平台,不断迭代,有大量案例,使用别人做好的h5需要付费。生态圈还不错。
  • 初页:手机app,手机端快速制作h5。
  • Epub360意派:设计师友好,自称专业级的。

类似的平台还有很多,一直纳闷如此多同类产品是如何生存的,目前看易企秀通过付费制作的方式经营的还不错,但是淘宝上有很多仿该平台的源码,很便宜。未来的发展和商业模式并不明朗。

以上的几个公司主要关注的是展示营销类的h5,对于h5游戏涉猎不多。对于h5游戏做的比较好的火舞游戏,百度h5游戏中心07073游戏 等。

好啦,什么商业模式,什么产品思维,什么设计理念,我们都不懂,我们就是写代码的,那就来干货吧,这样才能好好干活。

h5制作的相关技术

h5的动画受制于web浏览器的局限,基本有三种动画的实现方式。

  • 基于css的动画实现
  • 基于svg
  • 基于canvas
  • webgl

实践证明,当遇到复杂动画时,动画性能比较大致是这样的:svg < css < canvas < webgl

使用css实现:

css3确实要比过去强大很多,支持2d,3d的位移,缩放,透明度变化,旋转,过渡动画等,主要依赖css里的transform,transition,animation等属性,具体的使用方法参见w3school的教程。

需要注意的是 transition和animation不能同时作用于相同的元素.

当然也有很多的基于css的动画框架,让你快速构建动画。比较常用的有两类,css库和基于css动画的js库。

1.css库:css动画都是全局的,调用比较简单,但是侵入性比较强,固定模式,不太灵活。

  • animated.css 最常用的低调的动画库
  • hover.css 鼠标hover状态的动画库,移动端不可用
  • magic animation 比animate.css 奔放的动画库,动画尺度大
  • spinkit 几种css loading动画,不常用。
  • buttons.css 炫酷的按钮动画库,尤其是3d的按钮,是你想要的。

2.js库

京ICP备18057842号-1