前端面试总结

一、CSS相关问题

1、 行内元素,块级元素,空元素

  • 行内元素有:a b span select strong(强调的语气)
  • 块级元素有:div ul ol li dl dt dd h1 h2 h3 h4…p
  • 行内块元素:img, input, textarea
  • 常见的空元素:
    <br> <hr> <img> <input> <link> <meta>
    鲜为人知的是:
    <area> <base> <col> <command> <embed> <keygen> <param> <source> <track> <wbr>

2、选择器优先级

important(1,0,0,0) > 内联 > id(0,1,0,0) > class(0,0,1,0) = 属性 = 伪类( 0,0,1,0) >标签(0,0,0,1) = 伪元素(0,0,0,1) > 通配符(* 0,0,0,0)

3、水平垂直居中

  • 定位 + transform
//父元素设置position: relative;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
  • 行内块元素 + 标尺

1.给它的父元素写text-align属性;
2.要居中的元素将其类型转为inline-block;
3.要居中的元素加vertical-align属性;
4.添加一个“标尺”,既同级元素(span等),要居中的元素与其互相垂直居中
注意在编辑时标尺与需要居中的元素之间不能有空格回车;
标尺须加:

  display:inline-block;
  //目的是隐藏标尺
  width:0;
  //与父元素等高,中线位置既是居中位置
  height:100%;
  vertical-align:middle;
<style>
  *{
      margin: 0;
      padding: 0;
  }
  .div1{
      width: 200px;
      height: 150px;
      background: blue;
      margin: 20px 20px;
      text-align: center;
  }
  .div1-1{
      width: 100px;
      height: 100px;
      background: red;
      display: inline-block;
      vertical-align: middle;
  }
  .div1 span{
      display: inline-block;
      width: 0px;
      height: 100%;
      background: #0681D0;
      vertical-align: middle; 
  }
</style>
<div class="div1">div1
    <div class="div1-1">div2</div><span></span>
</div>

4、动画问题

5、写个左右布局,左边固定宽度,右边自适应

  • 左浮动 + 右不设宽(使用float需要注意清除浮动造成父元素塌陷的问题)
  • 左定位 + 右不设宽
  • flex布局

6、写六点筛子布局

image.png
  • flex布局
<style>
h2{
    text-align: center;
}

.main{
    display: flex;
    flex-wrap: wrap;
    width: 680px;
    justify-content: space-between;
}

.container{
    display: flex;
    width: 320px;
    height: 320px;
    flex-wrap: wrap;
    justify-content: space-between;
    align-content:space-between;
}

.box{
    width: 90px;
    height: 90px;
    background-color: #EEEEEE;
    padding: 5px;
    border-radius: 5px;
    display: flex;
    flex-wrap: wrap;            
}

.row{
    display: flex;
    flex-basis: 100%;
}

.item{
    width: 24px;
    height: 24px;
    background-color: #000000;
    margin: 3px;
    border-radius: 50%;
}
    

/*排列方向*/
.flex-direction-column{
     flex-direction: column;
}

/*水平排列*/
.justify-content-center{
    justify-content: center;
}

.justify-content-flex-end{
    justify-content: flex-end;
}

.justify-content-space-between{
    justify-content: space-between;
}
    
/*垂直排列*/
 .align-items-center{
     align-items: center;
 }

 .align-items-flex-end{
     align-items: flex-end;
 }

 .align-items-space-between{
     align-items: space-between;
 }

/*多轴对齐*/
 .align-content-space-between{
    align-content: space-between;
 }

 /*项目排列*/
 .align-self-center{
    align-self: center;
 }

 .align-self-flex-end{
    align-self: flex-end;
 }
</style>
<div class="container">
    <div class="box justify-content-center align-items-center">
        <span class="item"></span>
    </div>
    
    <div class="box justify-content-space-between">
        <span class="item"></span>
        <span class="item align-self-flex-end"></span>
    </div>
    
    <div class="box">
            <span class="item"></span>
            <span class="item align-self-center"></span>
            <span class="item align-self-flex-end"></span>
    </div>
    
    <div class="box align-content-space-between">
        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
        
        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
    </div>

    <div class="box">
        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
        
        <div class="row justify-content-center">
            <span class="item"></span>
        </div>

        <div class="row justify-content-space-between">
            <span class="item"></span>
            <span class="item"></span>
        </div>
    </div>

    <div class="box align-content-space-between flex-direction-column">
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
        <span class="item"></span>
    </div>
</div>


二、JS

1、js基本类型,如何判别类型

数据类型分为基本类型和引用类型:

  • 基本类型:String、Number、Boolean、Null、Undefined、symbol(ES6)

  • 引用类型:Object、Array、Date、Function、Error、RegExp、Math、Number、String、Boolean、Globle。

  • js内置类型有七种:String、Number、Boolean、Null、Undefined、Symbol(ES6)、Object

判断数据类型的几种方式优缺点对比
不同类型的优缺点 typeof instanceof constructor object.prototype.toString.call()
优点 使用简单 能检测出引用类型 基本能检测出所有类型(null和Undefined除外) 所有类型
缺点 基本类型(null不行) 基本类型不行,且不能跨iframe constructor易修改,且不能跨iframe IE6以下null和Undefined为Object

2、js数组的方法都看下

image.png

注意: 可参考https://www.cnblogs.com/sqh17/p/8529401.html

数组方法 作用 返回值 备注
arr.push() 从后面添加元素 添加完后的数组的长度
arr.pop() 从后面删除元素 删除的元素 只能删除一个
arr.shift() 从前面删除元素 删除的元素 只能删除一个
arr.unshift() 从前面添加元素 添加完后的数组的长度
arr.splice(i,n) 删除从i(索引值)开始之后的那个元素 删除的元素
arr.concat(i,n) 连接两个数组 连接后的新数组
arr.split() 将字符串转化为数组 数组
arr.sort() 将数组进行排序 排好的数组 默认是按照最左边的数字进行排序(1,10,2)
arr.reverse() 将数组反转 反转后的数组
arr.slice(start,end) 切去索引值start到索引值end的数组,不包含end索引的值 切出来的数组
arr.forEach(callback) 遍历数组,无return 会影响原来的数组
arr.map(callback) 映射数组(遍历数组) 返回一个新数组 数组长度与原数组相同(不满足同条件的为空)
arr.filter(callback) 过滤数组 返回一个新数组 实际满足条件的数组
arr.every(callback) 依据判断条件,数组的元素是否全满足 ture/false 全满足返回true
arr.some() 依据判断条件,数组的元素是否全满足 ture/false 若有一个满足则返回ture
arr.find(callback) 找到第一个符合条件的数组成员
arr.reduce(callback, initialValue) 迭代数组的所有项,累加器,数组中的每个值(从左到右)合并,最终计算为一个值 返回一个值
arr.indexOf() 查找某个元素的索引值 若有重复的,则返回第一个查到的索引值若不存在,则返回 -1 从前向后查找
arr.lastIndexOf() 查找某个元素的索引值 若有重复的,则返回第一个查到的索引值若不存在,则返回 -1 从后往前查找
Array.from() 将伪数组变成数组 数组 就是只要有length的就可以转成数组(ES6)
Array.of() 将一组值转换成数组,类似于声明数组
arr.copyWithin() 在当前数组内部,将制定位置的数组复制到其他位置 返回当前数组 会覆盖原数组项
arr.findIndex(callback) 找到第一个符合条件的数组成员的索引值
arr.fill(target, start, end) 使用给定的值,填充一个数组 填充完后会改变原数组
arr.includes() 判断数中是否包含给定的值 返回的是布尔值
arr.keys() 遍历数组的键名
arr.values() 遍历数组键值
arr.entries() 遍历数组的键名和键值
    let a = [1,2,3,4];
    let b = [1,2,3,4];
    let c = [1,2,3,4];
    let d = [1,2,3,4];
    let e = [1,2,3,4];
    let newA = [];

    a.forEach(item => {
        if (item > 2){
            newA.push(item)
        }
    })
    console.log(newA, a);

    let newB = b.map(item => {
        if (item > 2){
            return item
        }
    })
    console.log(newB, b);

    let newC = c.filter(item => {
        if (item > 2){
            return item
        }
    })
    console.log(newC, c)

    let D= d.every(item => {
        return item > 2
    })
    console.log(D, d)

    let E = e.some(item => {
        return item > 2
    })
    console.log(E, e)
image.png

3、原型链 new的作用

3.1、原型链

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。——摘自《javascript高级程序设计》

image.png
3.2、new的作用

1.创建一个空对象 p
2.把这个空对象 p 的属性 __proto__ 指向函数 Person 的 prototype
3.将构造函数 Person 的作用域赋给新对象 p,即 this 指向了 p
4.执行Person 中的代码,为p添加属性 name
5.返回新对象。

4、js有哪些作用域 闭包问题 写防抖函数

4.1 作用域

1、定义:作用域是在运行时代码中的某些特定部分中变量,函数和对象的可访问性。换句话说,能够访问另一个函数作用域的变量的函数
2、全局作用域、函数作用域、块级作用域(ES6)

4.2 闭包
4.2.1、定义

当内部函数被保存到外部时,会形成闭包;闭包会导致原始作用域链不释放,造成内存泄漏(占用);

function a() {
    var i = '初始值';
    i = i + "—_执行a"
    // 此处的函数b访问了父级函数a中的局部变量i,成为了一个闭包
    function b() {
        i = i + "_执行b"
        console.log(i)
    }
    return b;
}
var c = a(); // 此时 i 的值为 :初始值—_执行a
c()          // 此时 i 的值为 :初始值—_执行a_执行b
c()          // 此时 i 的值为 :初始值—_执行a_执行b_执行b

以上方代码为例:

  • 将函数a赋值给全局变量c时,a会执行一次,局部变量 i 的值变为初始值—_执行a,最终返回函数b,此时全局变量c的值为闭包函数b的引用。
    此时函数a虽然已执行完,但因为内部包含闭包函数b,所以函数 a 的执行期上下文会继续保留在内存中,不会被销毁,所以局部变量 i 仍是初始值—_执行a

执行期上下文:当函数执行时,会创建一个执行期上下文的内部对象。每调用一次函数,就会创建一个新的上下文对象,他们之间是相互独立的。当函数执行完毕,它所产生的执行期上下文会被销毁

  • 1、第一次执行 c() 时,闭包函数b第一次执行,局部变量 i 的值变为初始值—_执行a_执行b
  • 2、第二次执行 c() 时,闭包函数b第二次执行,局部变量 i 的值变为初始值—_执行a_执行b_执行b
4.2.2、闭包的特点
  • 1.被闭包函数访问的父级及以上的函数的局部变量(如范例中的局部变量 i )会一直存在于内存中,不会被JS的垃圾回收机制回收。
  • 2.闭包函数实现了对其他函数内部变量的访问。(函数内部的变量对外是无法访问的,闭包通过这种变通的方法,实现了访问。)
4.2.3、Javascript的垃圾回收机制
  • 如果一个对象不再被引用,那么这个对象就会被GC回收。
  • 如果两个对象互相引用,而不再被第三者所引用,那么这两个对象都会被回收。
    eg:
function person(name) {
    function say(content) {
        console.log(name + ':' + content)
    }
    return say
}

a = person("张三")
b = person("李四")
a("在干啥?")
b("没干啥。")
a("出去玩吗?")
b("去哪啊?")
4.2.4、优缺点
  • 优点:
    可以减少全局变量的定义,避免全局变量的污染
    能够读取函数内部的变量
    在内存中维护一个变量,可以用做缓存

  • 缺点:
    1)造成内存泄露
    闭包会使函数中的变量一直保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。(解决方法——使用完变量后,手动将它赋值为null;)
    2)闭包可能在父函数外部,改变父函数内部变量的值。
    3)造成性能损失
    由于闭包涉及跨作用域的访问,所以会导致性能损失。
    (解决方法——通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响)

4.3、函数防抖(debounce)

当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

实际场景:
连续的事件,只需触发一次的回调场景有:
1、搜索框搜索输入。
2、只需要用户最后一次输入完再发送请求 手机号、邮箱格式的输入验证检测
3、窗口大小的resize 。只需窗口调整完成后,计算窗口的大小,防止重复渲染

function debounce(fn, wait) {    
    var timeout = null;    
    return function() {        
        if(timeout !== null)   clearTimeout(timeout);        
        timeout = setTimeout(fn, wait);    
    }
}
// 处理函数
function handle() {    
    console.log(Math.random()); 
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
//当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。
4.4、 函数节流(throttle)

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。

间隔一段时间执行一次回调的场景有:
1、滚动加载,加载更多或滚动到底部监听;
2、谷歌搜索框,搜索联想功能;
3、高频点击提交,表单重复提交
4、省市信息对应字母快速选择

//节流 时间戳的方式实现
var throttle = function(func, delay) {            
  var prev = Date.now();            
  return function() {                
    var context = this;                
    var args = arguments;                
    var now = Date.now();                
    if (now - prev >= delay) {                    
      func.apply(context, args);                    
      prev = Date.now();                
    }            
  }        
}        
function handle() {            
  console.log(Math.random());        
}        
window.addEventListener('scroll', throttle(handle, 1000));


// 节流throttle代码(定时器):
var throttle = function(func, delay) {            
    var timer = null;            
    return function() {                
        var context = this;               
        var args = arguments;                
        if (!timer) {                    
            timer = setTimeout(function() {                        
                func.apply(context, args);                        
                timer = null;                    
            }, delay);                
        }            
    }        
}        
function handle() {            
    console.log(Math.random());        
}        
window.addEventListener('scroll', throttle(handle, 1000));

5、promise的使用 原理 所拥有的方法

1、Promise 的含义
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

2、基本用法
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例。
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve(成功)和reject(失败)。它们是两个函数,将异步操作的结果,作为参数传递出去

3、所拥有的方法
Promise.prototype.catch() catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数
Promise.prototype.finally() finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
Promise.all() all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例(所有的都成功了才执行)
Promise.race()race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
Promise.resolve()将现有对象转为 Promise 对象,Promise.resolve方法就起到这个作用
Promise.reject()将现有对象转为 Promise 对象,Promise.reject方法就起到这个作用(参数作为reject的理由)
Promise.try()为所有操作提供了统一的处理机制,可以更好地管理异常
详情见https://www.jianshu.com/p/d8a901dd72ac

6、es6有哪些特性 箭头函数和普通函数区别

1、箭头函数
1.1 更简洁的语法
1.2 没有this
1.3 不能使用new 构造函数
1.4 不绑定arguments,用rest参数...解决
1.5 使用call()和apply()调用
1.6 捕获其所在上下文的 this 值,作为自己的 this 值
1.7 箭头函数没有原型属性
1.8 不能简单返回对象字面量
1.9 箭头函数不能当做Generator函数,不能使用yield关键字
1.10 箭头函数不能换行

//1、没有形参的时候
let fun = () => console.log('我是箭头函数'); 
fun();
//2、只有一个形参的时候()可以省略
let fun2 = a => console.log(a); 
fun2('aaa');

//3、俩个及俩个以上的形参的时候
let fun3 = (x,y) =>console.log(x,y);  //函数体只包含一个表达式则省略return 默认返回
fun3(24,44);

//4、俩个形参以及函数体多条语句表达式
let fun4 = (x,y) => {
  console.log(x,y);
  return x+y; //必须加return才有返回值
}
//5、如果要返回对象时需要用小括号包起来,因为大括号被占用解释为代码块了,正确写法
let fun5 = ()=>({ foo: x })   //如果x => { foo: x }  //则语法出错

7、函数柯里化 纯函数

自己百度吧, 看不懂。
https://www.jianshu.com/p/2975c25e4d71

8、数据不可变 immutable原理

自己百度吧, 看不懂。
https://segmentfault.com/a/1190000016404944

9、js bind函数的性能问题(https://blog.csdn.net/ywl570717586/article/details/74231402)

10、js怎么定义一个不可改值的对象

Javascipt的数据属性有一个名为Writable的特征, 可以用于设置属性值是否可以被修改(Object.defineProperty方法接收三个参数:需要添加或修改属性的对象,属性名称,属性描述options(writable:false))

11、const 定义常量可以改变吗

const所说的常量,是指,对应的指针或者说地址是常量
const定义的基本数据类型的变量不可以修改,但其它复杂数据类型是可以修改的
用const定义的数组,里面的元素是可变的

如何定义不可改变的数组:
Object.preventExtendsion(obj) 用来禁止对象可扩展其它属性(阻止对象新增属性,但可改变)
Object.seal(obj)用来禁止对象删除其它属性和扩展其它属性(阻止对象删除属性,但可改变)
Object.freeze(obj)用来冻结对象,就是所有的属性不能够更改和新增(阻止对象更改和新增属性)

详情见:https://blog.csdn.net/weixin_33697898/article/details/91371632

12、深拷贝/浅拷贝

  • 1、基本类型--名值存储在栈内存中,例如let a=1;
  • 2、引用数据类型--名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值

三、浏览器

1、cookie安全

指某些网站为了辨别用户身份、进行session跟踪而存储在用户本地终端上的数据(通常经过加密)

生命周期:
创建cookie的时候,会给cookie指定一个值:Expire,它就是指定cookie的有效期,也就是cookie的生命周期,超出设置的这个生命周期,cookie就会被清除。如果给这个值Expire设置为0或者负值,那么这样的设置就是在关闭浏览器时,就会清除cookie,这种方式更加安全。

如何解决cookie安全性问题
第一步:设置cookie有效期不要过长,合适即可
第二步:设置HttpOnly属性为true(可以防止js脚本读取cookie信息,有效的防止XSS攻击)。
第三步:设置复杂的cookie,加密cookie(尽可能使得加密后的cookie更难解密,也是保护了cookie中的信息)
(1)cookie的key使用uuid,随机生成;
(2)cookie的value可以使用复杂组合,比如:用户名+当前时间+cookie有效时间+随机数。
第四步:用户第一次登录时,保存ip+cookie加密后的token(每次请求,都去将当前cookie和ip组合起来加密后的token与保存的token作对比,只有完全对应才能验证成功)
第五步:session和cookie同时使用(sessionId虽然放在cookie中,但是相对的session更安全,可以将相对重要的信息存入session)
第六步:如果网站支持https,尽可能使用https(为cookie设置Secure属性为true,它的意思是,cookie只能使用https协议发送给服务器,而https比http更加安全)

2、宏任务 微任务

setTimeout(() => {
  //宏任务,放到Event Queue(宏任务队列)中
  console.log('1')
});

new  Promise((resolve) => {
  //主线程,直接执行
  console.log('2');
  resolve();
}).then(() => {
  //微任务 放到Event Queue(微任务队列)中
  console.log('3')
});
//主线程,直接执行
 console.log('4');

执行结果: 2,4,3,1
解释如下:
先看执行的代码是同步任务还是异步任务,同步的主线程直接执行,异步任务放到任务队列中。

image.png

任务队列中,先执行一个宏任务,若有微任务,执行所有的微任务之后,再做新的宏任务。

image.png

image.png

https://www.cnblogs.com/wangziye/p/9566454.html

3、页面加载过程

  • 1、输入的网址在通过DNS解析后得到服务器地址浏览器向服务器发起http请求,经过TCP/IP三次握手确认链接后,服务器将需要的代码发回给浏览器。
  • 2、浏览器接收到代码后进行解析,经过三大步骤:DOM构造、布局以及绘制页面
  • 2.1、DOM构造
    浏览器首先将收到的html代码,通过html解析器解析构建为一颗DOM树。数据结构中有许多的树,而DOM树就像是一颗倒长着的大树,这样的对象模型决定了节点之间都有一定的关联它们关系可能有父子、有兄弟,我们可以顺着这颗树做出许多操作。
    接着将接收到的css代码,通过css解析器构建出样式表规则将这些规则分别放到对应的DOM树节点上,得到一颗带有样式属性的DOM树。
  • 2.2、布局
    浏览器按从上到下,从左到右的顺序,读取DOM树的文档节点,顺序存放到一条虚拟的传送带上。传送带上的盒子就是节点,而这条流动的传送带就是文档流。如果我们读取到的节点是属于另一个节点下的子节点,那么在放入传送带的时候,就应该按顺序放到该节点盒子的内部。如果子节点下还有子节点,在传送带上的时候就继续套到子一级的盒子内部。根据它在DOM树上的结构,可以嵌套的层级没有限制的哦。文档流排完之后,开始获取计算节点的坐标和大小等CSS属性,作为盒子的包装说明。然后把盒子在仓库里一一摆放,这就将节点布局到了页面。
  • 2.3、绘制页面
    布局完成之后,我们在页面上其实是看不到任何内容的浏览器只是计算出了每一个节点对象应该被放到页面的哪个位置上,但并没有可视化。因此最后一步就是将所有内容绘制出来,完成整个页面的渲染。
    https://www.zhihu.com/question/30218438

4、https ssl加密如何实现

5、跨域如何解决

  • 1、 通过jsonp跨域(jsonp缺点:只能实现get一种请求)
  • 2、 document.domain + iframe跨域(此方案仅限主域相同,子域不同的跨域应用场景。)
  • 3、 location.hash + iframe
  • 4、 window.name + iframe跨域(window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值2MB)

总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

  • 5、 postMessage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.) 多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
d.) 上面三个场景的跨域数据传递
用法
postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"

  • 6、 跨域资源共享(CORS)

  • 7、 nginx代理跨域

  • 8、 nodejs中间件代理跨域


    image.png
  • 9、 WebSocket协议跨域

https://segmentfault.com/a/1190000011145364

四、框架

4.1、react

1、react生命周期,原理,虚拟dom理解,diff算法原理

2、react版本都更新了什么,最新版本去掉什么生命周期加入什么生命周期,为什么

3、组件渲染优化

4、如何理解高阶组件

5、redux理念是什么 单数据流如何改变的

6、webpack有哪些配置属性 原理 插件如何实现

7、bable的配置属于有哪些 浏览器兼容性

8、AST语法树

9、小程序父子组件通讯,wepy父子组件通讯

10、react创建组件的方法(React.createClass React.Component 函数定义无状态组件)

11、react无状态组件和pureComponent区别

12、react什么时候setstate是同步的(一步操作中调用)

13、react组件间怎么通讯---react原生方法(都是事件机制啊实在找不到)

14、react父组件拿子组件ref(this.refs.xxx.refs.textinput

15、react将组件渲染到指定dom节点(https://blog.csdn.net/neoveee/article/details/57399834

16、webpack插件有哪些(extract-text-webpack-plugin单独打包css),怎么多个入口,怎么打包成内联样式??? ,不打包某个文件??

17、React如何实现vue中的插件模式???

react没有实际开发经验,等有经验了再整理吧

4.2、vue

9、vue的双向数据流如何实现

vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的

Object.defineProperty()这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。


var obj = { };
var name;
//第一个参数:定义属性的对象。
//第二个参数:要定义或修改的属性的名称。
//第三个参数:将被定义或修改的属性描述符。
Object.defineProperty(obj, "data",  {
//获取值get: 
function () { return name; },
//设置值set: 
function (val) {
    name = val;
    console.log(val)}
})
//赋值调用
setobj.data = 'aaa';
//取值调用
getconsole.log(obj.data);
// 代码演示:defineProperty的双向绑定
var obj = {};
Object.defineProperty(obj, 'val', {
    set: function (newVal) {
        document.getElementById("a").value = newVal == undefined ? '' : newVal;
        document.getElementById("b").innerHTML = newVal == undefined ? '' : newVal;
    }
});
document.getElementById("a").addEventListener("keyup", function (e) {
    obj.val = e.target.value;
})

computed 计算属性与method方法的区别

computed中的计算属性可以写在method中,区别就是method调用要加()而computed不用

computed中必须要加return

computed里面的方法不是通过事件去触发的,而是当属性(必须是data中的属性)发生改变的时候那么当前函数就会被触发

最大的区别是,computed中有缓存,相同的值会直接拿已经缓存的,提高性能,但是method没有缓存,一样的值还是会重新获取

1、Vue循环为什么要加key

key属性可以用来提升v-for渲染的效率,vue中使用v-for渲染数据的时候,并不会去改变原有的元素和数据,而是创建新的元素,再把新的数据渲染进去。

2、Vue循环为什么不用index作为key

index 作为 key,和没写基本上没区别,因为不管你数组的顺序怎么颠倒,index 都是 0, 1, 2 这样排列,导致 Vue 虚拟DOM的复用会映射到错误的旧子节点,做很多额外的工作,影响效率。

vue原理 数据劫持 路由守卫怎么用 axios怎么写请求拦截 响应拦截

10vuex如何数据绑定的

11vue有哪些框架优缺点

五、Reactnative

1有哪些坑,怎么解决

2热更新问题

3性能问题,比如列表

4首屏白屏怎么解决

5自己封装过什么组件

6js和原生通讯方法有哪些 jsbridge原理

Node

1用来做什么

2用过哪些框架

3express如何解决异步问题

4node从哪个版本开始有Async和Await

5node数据流如何理解

6如何理解中间价

7node如何确保稳定性,进程死了如何自动修复

六、网络

1tcp三次握手

2分析请求头

算法

1随机一个数组,数组每个值区间2-32

2最长回文字段

开放性问题

1flutter有使用过吗,你感觉如何

2全局有console的地方全部换成弹框显示

3如何优化pc和app

4项目如何发布部署,如何本地开发,git使用等

函数式编程

函数式编程(缩写为 FP)是一种通过组合纯函数来构建软件的过程,避免状态共享、可变数据及副作用的产生。

1、函数式编程定义

image.png

2、函数式编程的特点

    1. 函数是"第一等公民"
      把它想象成一个数据类型,可以声明、赋值给其他变量、当参数传给函数等等
    1. 只用"表达式",不用"语句"
      "表达式"(expression):是一个单纯的运算过程,总是有返回值;
      "语句"(statement):是执行某种操作,没有返回值。
      函数式编程要求,只使用表达式,不使用语句。也就是说,每一步都是单纯的运算,而且都有返回值。
    1. 没有"副作用"
      所谓"副作用",指的是函数内部与外部互动(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。
      函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。
    1. 不修改状态
      函数式编程只是返回新的值,不修改系统变量。因此,不修改变量,也是它的一个重要特点。
    1. 引用透明
      引用透明(Referential transparency),指的是函数的运行不依赖于外部变量或"状态",只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的。
      方法传入的参数类型与返回值类型是一样的(类比map,same方法,传入一个数组同时返回的也是一个数组)
      来自:http://www.ruanyifeng.com/blog/2012/04/functional_programming.html

undenfine 和null 有什么区别 做if判断会怎样

http://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html

image.png

vue数据劫持

  • 针对 Object 类型,采用 Object.defineProperty() 方法劫持属性的读取和设置方法;
  • 针对 Array 类型,采用原型相关的知识劫持常用的函数,从而知晓当前数组发生变化。
    注意: Object.defineProperty() 方法存在以下缺陷:
    每次只能设置一个具体的属性,导致需要遍历对象来设置属性,同时也导致了无法探测新增属性;
    属性描述符 configurable 对其的影响是致命的。而 ES6 中的 Proxy 可以完美的解决这些问题

raw-loader:加载文件原始内容(utf-8)
file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)
source-map-loader:加载额外的 Source Map 文件,以方便断点调试
svg-inline-loader:将压缩后的 SVG 内容注入代码中
image-loader:加载并且压缩图片文件
json-loader 加载 JSON 文件(默认包含)
handlebars-loader: 将 Handlebars 模版编译成函数并返回
babel-loader:把 ES6 转换成 ES5
ts-loader: 将 TypeScript 转换成 JavaScript
awesome-typescript-loader:将 TypeScript 转换成 JavaScript,性能优于 ts-loader
sass-loader:将SCSS/SASS代码转换成CSS
css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS
postcss-loader:扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀
eslint-loader:通过 ESLint 检查 JavaScript 代码
tslint-loader:通过 TSLint检查 TypeScript 代码
mocha-loader:加载 Mocha 测试用例的代码
coverjs-loader:计算测试的覆盖率
vue-loader:加载 Vue.js 单文件组件
i18n-loader: 国际化
cache-loader: 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里
有哪些常见的Plugin?你用过哪些Plugin?
define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
ignore-plugin:忽略部分文件
html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)
web-webpack-plugin:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用
uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前)
terser-webpack-plugin: 支持压缩 ES6 (Webpack4)
webpack-parallel-uglify-plugin: 多进程执行代码压缩,提升构建速度
mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin)
serviceworker-webpack-plugin:为网页应用增加离线缓存功能
clean-webpack-plugin: 目录清理
ModuleConcatenationPlugin: 开启 Scope Hoisting
speed-measure-webpack-plugin: 可以看到每个 Loader 和 Plugin 执行耗时 (整个打包耗时、每个 Plugin 和 Loader 耗时)
webpack-bundle-analyzer: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)
Loader和Plugin的区别?
Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。
Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。

const HtmlWebpackPlugin = require('html-webpack-plugin');
// 有时我们会指定打包文件中带有 hash,那么每次生成的 js 文件名会有所不同,不能让我们每次都人工去修改 html,
// 我们可以使用 html-webpack-plugin 插件来帮助我们完成这些事情。
// 有时候,我们的脚手架不仅仅给自己使用,也许还提供给其它业务使用,html 文件的可配置性可能很重要,比如:你公司有专门的部门提供M页的公共头部/公共尾部,埋点jssdk以及分享的jssdk等等,但是不是每个业务都需要这些内容。
// 一个功能可能对应多个 js 或者是 css 文件,如果每次都是业务自行修改 public/index.html 文件,也挺麻烦的。首先他们得搞清楚每个功能需要引入的文件,然后才能对 index.html 进行修改。
// 此时我们可以增加一个配置文件,业务通过设置 true 或 false 来选出自己需要的功能,我们再根据配置文件的内容,为每个业务生成相应的 html 文件,岂不是美美的。

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    // 每次 clean-webpack-plugin 都会帮我们先清空一波 dist 目录的插件
const CopyWebpackPlugin = require('copy-webpack-plugin');
    // 静态资源拷贝插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 抽离CSS,即将CSS文件单独打包的插件,这可能是因为打包成一个JS文件太大,影响加载速度,也有可能是为了缓存
const OptimizeCssPlugin = require('optimize-css-assets-webpack-plugin');
// 使用 mini-css-extract-plugin,CSS 文件默认不会被压缩,如果想要压缩,需要配置 optimization插件

// import() 语法,
// 按需加载
// 需要 @babel/plugin-syntax-dynamic-import 的插件支持,
// 但是因为当前 @babel/preset-env 预设中已经包含了 @babel/plugin-syntax-dynamic-import,因此我们不需要再单独安装和配置。

const webpack = require('webpack');
const path = require('path');
const isDev = process.env.NODE_ENV === 'development';
const config = require('./public/config')[isDev ? 'dev' : 'build'];

module.exports = {
    mode: isDev ? 'development' : 'production',
    // mode 配置项,告知 webpack 使用相应模式的内置优化。
    // mode 配置项,支持以下两个配置:
    // development:将 process.env.NODE_ENV 的值设置为 development,启用 NamedChunksPlugin 和 NamedModulesPlugin
    // production:将 process.env.NODE_ENV 的值设置为 production,启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin
    
    
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // entry 的值可以是一个字符串,一个数组或是一个对象。
    // 字符串的情况无需多说,就是以对应的文件为入口。
    // 为数组时,表示有“多个主入口”,想要多个依赖文件一起注入时
    
    
    output: {
        path: path.resolve(__dirname, 'dist'), //必须是绝对路径
        filename: 'bundle.[hash:6].js',
        publicPath: '/' //通常是CDN地址
    },
    // 例如,你最终编译出来的代码部署在 CDN 上,资源的地址为: 'https://AAA/BBB/YourProject/XXX',那么可以将生产的 publicPath 配置为: //AAA/BBB/。
// 编译时,可以不配置,或者配置为 /。可以在我们之前提及的 config.js 中指定 publicPath(config.js 中区分了 dev 和 public), 当然还可以区分不同的环境指定配置文件来设置,或者是根据 isDev 字段来设置。
    

    module: {
        // loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript),用于对源代码进行转换
        rules: [
            {
                test: /\.jsx?$/, //匹配规则,针对符合规则的文件进行处理。
                use: {
                    loader: 'babel-loader', 
                    options: {      //这里,我们可以在 .babelrc 中编写 babel 的配置,也可以在 webpack.config.js 中进行配置。
                        presets: ["@babel/preset-env"],
                        plugins: [
                            [
                                "@babel/plugin-transform-runtime",
                                {
                                    "corejs": 3
                                }
                            ]
                        ]
                    }
                },
                exclude: /node_modules/ //排除 node_modules 目录
            },
            // 讲js转译为低版本
            {
                test: /.html$/,
                use: 'html-withimg-loader'
            },
            // 处理在html中引入的本地图片
            
            // use 字段有几种写法
            // 可以是一个字符串,例如上面的 use: 'html-withimg-loader'
            // use 字段可以是一个数组,例如处理CSS文件时,use: ['style-loader', 'css-loader']
            // use 数组的每一项既可以是字符串也可以是一个对象,当我们需要在webpack 的配置文件中对 loader 进行配置,就需要将其编写为一个对象,
            // 并且在此对象的 options 字段中进行配置。
            // loader 的执行顺序是从右向左执行的,也就是后面的 loader 先执行,下面 loader 的执行顺序为: less-loader ---> postcss-loader ---> css-loader ---> style-loader
            // 当然,loader 其实还有一个参数,可以修改优先级,enforce 参数,其值可以为: pre(优先执行) 或 post (滞后执行)。
            {
                test: /\.(le|c)ss$/,
                use: [
                    // 'style-loader', 
                    MiniCssExtractPlugin.loader, //替换之前的 style-loader
                    'css-loader', {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function () {
                            return [
                                require('autoprefixer')()
                            ]
                        }
                    }
                }, 'less-loader'],
                exclude: /node_modules/
            },
             // style-loader 动态创建 style 标签,将 css 插入到 head 中.
             // css-loader 负责处理 @import 等语句。
             // postcss-loader 和 autoprefixer,自动生成浏览器兼容性前缀 
             // less-loader 负责处理编译 .less 文件,将其转为 css
            {
                test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10240, //10K
                            esModule: false,
                            outpath:'assets'
                        }
                    }
                ],
                exclude: /node_modules/
            },
            // 我们可以使用 url-loader 或者 file-loader 来处理本地的资源文件。
            // url-loader 和 file-loader 的功能类似,
            // 但是 url-loader 可以指定在文件大小小于指定的限制时,返回 DataURL,
            // 因此,个人会优先选择使用 url-loader
            // 当本地资源较多时,我们有时会希望它们能打包在一个文件夹下,这也很简单,我们只需要在 url-loader 的 options 中指定 outpath,如: outputPath: 'assets'
            // 此处设置 limit 的值大小为 10240,即资源大小小于 10K 时,将资源转换为 base64,超过 10K,将图片拷贝到 dist 目录。
            // esModule 设置为 false,否则,<img src={require('XXX.jpg')} /> 会出现 <img src=[Module Object] />
            // 将资源转换为 base64 可以减少网络请求次数,但是 base64 数据较大,如果太多的资源是 base64,会导致加载变慢,
            // 因此设置 limit 值时,需要二者兼顾。

           
        ]
    },
    devtool: isDev ? 'cheap-module-eval-source-map' : 'source-map',
    // devtool 中的一些设置,可以帮助我们将编译后的代码映射回原始源代码。不同的值会明显影响到构建和重新构建的速度。
    // 能够定位到源码的行即可,因此,综合构建速度,在开发模式下,设置 devtool 的值是 cheap-module-eval-source-map。
    // 生产环境可以使用 none 或者是 source-map,使用 source-map 最终会单独打包出一个 .map 文件,我们可以根据报错信息和此 map 文件,进行错误解析,定位到源代码。
    // source-map 和 hidden-source-map 都会打包生成单独的 .map 文件,区别在于,source-map 会在打包出的js文件中增加一个引用注释,以便开发工具知道在哪里可以找到它。hidden-source-map 则不会在打包的js中增加引用注释。
    // 但是我们一般不会直接将 .map 文件部署到CDN,因为会直接映射到源码,更希望将.map 文件传到错误解析系统,然后根据上报的错误信息,直接解析到出错的源码位置。


    plugins: [
        //数组 放着所有的webpack插件
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html', //打包后的文件名
            config: config.template,  //读取config配置文件生成不同的文件
            // hash: true //是否加上hash,默认是 false
            chunks: ['index'] //配置此参数仅会将数组中指定的js引入到html文件中,此外,如果你需要引入多个JS文件,仅有少数不想引入,还可以指定 excludeChunks 参数,它接受一个数组。
        }),
        new HtmlWebpackPlugin({
            template: './public/login.html',
            filename: 'login.html', //打包后的文件名
            chunks: ['login']
        }),
        // 多页面应用打包
        // 如果需要配置多个 HtmlWebpackPlugin,
        // 那么 filename 字段不可缺省,否则默认生成的都是 index.html,
        // 如果你希望 html 的文件名中也带有 hash,那么直接修改 fliename 字段即可,例如: filename: 'login.[hash:6].html'。

        new CleanWebpackPlugin({
            cleanOnceBeforeBuildPatterns:['**/*', '!dll', '!dll/**'] //不删除dll目录下的文件
        }),
        new CopyWebpackPlugin({
            patterns: [
                { 
                    from: 'public/js/*.js',   //将 public/js 目录拷贝至 dist/js 目录
                    to: path.resolve(__dirname, 'dist', 'js'),
                    flatten: true, //设置为 true,那么它只会拷贝文件,而不会把文件夹路径都拷贝上,
                    // ignore: ['other.js'] 忽略掉 js 目录下的 other.js 文件
                }
            ],
        }),
        new MiniCssExtractPlugin({
            filename: 'css/[name].css'
            //个人习惯将css文件放在单独目录下
            //publicPath:'../'   //如果你的output的publicPath配置的是 './' 这种相对路径,那么如果将css文件放在单独目录下,记得在这里指定一下publicPath 
        }),
        new OptimizeCssPlugin(),    //压缩css插件
        
        new webpack.HotModuleReplacementPlugin(), //热更新插件

        new webpack.DefinePlugin({              //定义环境变量插件      \
            DEV: JSON.stringify('dev'), //字符串
            //index.js
               // if(DEV === 'dev') {
                //     //开发环境
                // }else {
                //     //生产环境
                // }
            FLAG: 'true' //FLAG 是个布尔类型
        })
     
    ],

    devServer: {
        // port: '8888', //默认是8080
        // quiet: false, //默认不启用
        // inline: true, //默认开启 inline 模式,如果设置为false,开启 iframe 模式
        // stats: "errors-only", //终端仅打印 error
        // overlay: false, //默认不启用
        // clientLogLevel: "silent", //日志等级
        // compress: true //是否启用 gzip 压缩
        hot:true //热更新
    },
    // 启用 quiet 后,除了初始启动信息之外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见 ,不建议开启
    // stats: "errors-only" ,终端中仅打印出 error,注意当启用了 quiet 或者是 noInfo 时,此属性不起作用。
    // 启用 overlay 后,当编译出错时,会在浏览器窗口全屏输出错误,默认是关闭的。
    resolve: {
        modules: ['./src/components', 'node_modules'], //从左到右依次查找
        // resolve 配置 webpack 如何寻找模块所对应的文件。
        // webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你可以根据自己的需要修改默认的规则。
        extensions: ['web.js', '.js'] //当然,你还可以配置 .json, .css        
// extensions适配多端的项目中,可能会出现 .web.js, .wx.js,例如在转web的项目中,我们希望首先找 .web.js,如果没有,再找 .js。我们可以这样配置
    }
}

// 区分不同的环境
// 目前为止我们 webpack 的配置,都定义在了 webpack.config.js 中,对于需要区分是开发环境还是生产环境的情况,
// 我们根据 process.env.NODE_ENV 去进行了区分配置,但是配置文件中如果有多处需要区分环境的配置,这种显然不是一个好办法。
// 更好的做法是创建多个配置文件,如: webpack.base.js、webpack.dev.js、webpack.prod.js。
// 然后修改我们的 package.json,指定对应的 config 文件

// webpack.base.js 定义公共的配置
// webpack.dev.js:定义开发环境的配置
// webpack.prod.js:定义生产环境的配置

// webpack-merge 专为 webpack 设计,提供了一个 merge 函数,用于连接数组,合并对象。
// const merge = require('webpack-merge');
// merge({
//     devtool: 'cheap-module-eval-source-map',
//     module: {
//         rules: [
//             {a: 1}
//         ]
//     },
//     plugins: [1,2,3]
// }, {
//     devtool: 'none',
//     mode: "production",
//     module: {
//         rules: [
//             {a: 2},
//             {b: 1}
//         ]
//     },
//     plugins: [4,5,6],
// });
// //合并后的结果为
// {
//     devtool: 'none',
//     mode: "production",
//     module: {
//         rules: [
//             {a: 1},
//             {a: 2},
//             {b: 1}
//         ]
//     },
//     plugins: [1,2,3,4,5,6]
// }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,780评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,424评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,397评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,576评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,997评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,945评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,107评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,850评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,625评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,804评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,285评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,613评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,291评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,164评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,963评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,096评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,886评论 2 278

推荐阅读更多精彩内容