前端面试题

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。

IOS安装不了shadowscoks怎么办?

image
image
image

委托模式

我们再来看 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库

Canvas

annie2x

Annie2x是一款Adobe Flash的插件,支持Flash cc 2015及以上和Adobe Animate 全线版本
,通过Annie2x插件能将FLA文件直接 CTRL+ENTER 一键发布成小程序 小游戏 HTML5等

动画制作软件

3D

https://www.babylonjs.com/