認識JavaScript中的函數(shù)

前言:本文將詳細的介紹JS中函數(shù)的相關(guān)概念(包括函數(shù)的call stack 论皆、this 、作用域、閉包俊扭、柯里化萨惑、高階函數(shù)等)庸蔼,總結(jié)函數(shù)中比較容易理解錯的坑贮匕,讓我們更加全面的認識函數(shù)刻盐。部分概念與代碼參考阮一峰JS教程敦锌。


1乙墙、什么是函數(shù)

函數(shù)是一段可以反復(fù)調(diào)用的代碼塊听想。函數(shù)還能接受輸入的參數(shù),不同的參數(shù)會返回不同的值肛走。

函數(shù)的本質(zhì)就是對象朽色,或者說可以執(zhí)行代碼的對象就是函數(shù)葫男。
因此我們甚至可以使用寫純對象的方式來寫一個函數(shù)梢褐,讓我們更了解函數(shù)的本質(zhì):

var fn = {} ;
fn.params = ['x','y'] ; // 參數(shù)
fn.fbody = 'console.log(1)' ; //函數(shù)體
fn.call = function(){
    eval(fn.fbody)
}
fn.call() ; // 調(diào)用函數(shù)的call方法來執(zhí)行函數(shù)
// 1

如上述代碼盈咳,fn作為一個對象鱼响,使用call()方法執(zhí)行的效果和執(zhí)行函數(shù)是一樣的,當然fn只是個長得像函數(shù)的對象筐骇,只是為了便于我們理解函數(shù)的本質(zhì)铛纬。

注:上面代碼中使用了eval() 方法告唆,那么就在這里提一下:
eval命令的作用是悔详,將字符串當作語句執(zhí)行茄螃。eval() 方法是window的全局對象归苍。
eval('var a = 1;'); a // 1
一般情況下盡量避免使用該方法运怖。

2摇展、函數(shù)的五種聲明方法

注:函數(shù)體內(nèi)部的return語句咏连,表示返回祟滴。JavaScript 引擎遇到return語句垄懂,就直接返回return后面的那個表達式的值,后面即使還有語句匙头,也不會得到執(zhí)行乾胶。也就是說,return語句所帶的那個表達式脑融,就是函數(shù)的返回值肘迎。return語句不是必需的锻煌,如果沒有的話宋梧,該函數(shù)就不返回任何值捂龄,或者說返回undefined倦沧。

  • 具名函數(shù)的聲明
function fn1() {
   return undefined; // 如果不寫return 展融,瀏覽器默認添加
}  
  • 匿名函數(shù)的聲明
    var fn2 = function() {}

  • 結(jié)合上面兩種方式(謹慎使用)
    var fn3 = function fn4() {}

  • 使用Function函數(shù)對象來聲明

var fn5 = new Function(
  'x',
  'y',
  'return x + y'
);

其中new Function() 中告希,最后一個參數(shù)表示函數(shù)體暂雹,前面的參數(shù)表示傳入函數(shù)的參數(shù)杭跪。

  • 最酷炫的聲明方法:箭頭函數(shù)(詳情可見本文第14條)
    var fn6 = (x,y) => {return x+y}箭頭前面表示傳入函數(shù)的參數(shù),箭頭后面表示函數(shù)體檬贰。
    如果只有一個參數(shù)翁涤,參數(shù)的圓括號可以省略:
    var fn7 = x => {return x*2}
    如果函數(shù)體只有一句話葵礼,可以同時省略函數(shù)體的大括號及return
    var fn8 = x => x*x

3鸳粉、函數(shù)的調(diào)用

眾所周知届谈,函數(shù)的調(diào)用很簡單艰山,比如有這樣一個函數(shù)
function fn (){ return undefined; }
我們只需fn(); 即可執(zhí)行該函數(shù)曙搬。

但是作為初學者织鲸,更建議使用call()方法搂擦,比如有函數(shù):
function fn(x,y){ return x+y; }
就可以這么調(diào)用:fn.call(undefined,1,2) // 結(jié)果為3 等價于這么寫fn(1,2)
之所以建議初學者使用call()方法,因為這么寫更便于理解thisarguments
比如上面的那句調(diào)用哗脖,call()的第一個參數(shù)就是this瀑踢,后面的參數(shù)就是arguments

4、函數(shù)的常用屬性和方法

  • name 屬性
    每一個函數(shù)都有name屬性才避,你以為name屬性就真的是表示函數(shù)的名字而且很好理解嗎橱夭?
    明顯答案是否定的,使用不同的函數(shù)聲明方式桑逝,其name屬性的值可能就不是你想象中的樣子。下面舉例說明:
// 具名函數(shù)的name屬性 楞遏,表示函數(shù)的名字
function fn1() {} 
fn1.name // "fn1"

// 匿名函數(shù)的name屬性茬暇,指的是接收函數(shù)的變量名
var fn2 = function () {} 
fn2.name // "fn2"

// 下面這種聲明方法首昔,在外部獲取不到fn4函數(shù)
// 注:fn3.name返回函數(shù)表達式的名字。注意糙俗,真正的函數(shù)名還是fn3勒奇,而fn4這個名字只在函數(shù)體內(nèi)部可用。
var fn3 = function fn4(){} 
fn3.name // "fn4"

// 使用Function() 方法構(gòu)造函數(shù)巧骚,函數(shù)的name屬性值為"anonymous"
var fn5 = new Function()
fn5.name // "anonymous"

// 箭頭函數(shù)的name屬性赊颠,指的也是接收該函數(shù)的變量名
var fn6 = () => {}
fn6.name // "fn6"
  • length 屬性
    函數(shù)的length屬性返回函數(shù)預(yù)期傳入的參數(shù)個數(shù),即函數(shù)定義之中的參數(shù)個數(shù)劈彪。
    如:
function f(a, b) {}
f.length // 2

上面代碼定義了空函數(shù)f竣蹦,它的length屬性就是定義時的參數(shù)個數(shù)。不管調(diào)用時輸入了多少個參數(shù)沧奴,length屬性始終等于2草添。
注:length屬性提供了一種機制,判斷定義時和調(diào)用時參數(shù)的差異扼仲,以便實現(xiàn)面向?qū)ο缶幊痰摹狈椒ㄖ剌d“(overload)。

  • toString() 方法
    函數(shù)的toString方法返回一個字符串抄淑,內(nèi)容是函數(shù)的源碼屠凶,包括函數(shù)中的注釋也會被打印出來。如:
function f() {
  var a = 1
/*  這是一個
  多行注釋*/
}

f.toString()
//   "function f() {
//     var a = 1
//   /*  這是一個0
//     多行注釋*/
//   }"

5肆资、call & apply & bind 的用法

在 javascript 中矗愧,callapply 都是為了改變某個函數(shù)運行時的上下文(context)而存在的,換句話說郑原,就是為了改變函數(shù)體內(nèi)部 this 的指向唉韭。

  • call() 方法調(diào)用一個函數(shù), 其具有一個指定的this值和分別地提供的參數(shù)(參數(shù)的列表)。

  • apply() 方法調(diào)用一個函數(shù), 其具有一個指定的this值犯犁,以及作為一個數(shù)組(或類似數(shù)組的對象)提供的參數(shù)属愤。

  • bind() 方法創(chuàng)建一個新的函數(shù),被調(diào)用時酸役,將其this關(guān)鍵字設(shè)置為提供的值住诸,在調(diào)用新函數(shù)時,在任何提供之前提供一個給定的參數(shù)序列涣澡。

  • 對于apply贱呐、call二者而言,作用完全一樣入桂,只是接受參數(shù)的方式不太一樣奄薇,call需要把參數(shù)按順序傳遞進去,而 apply則是把參數(shù)放在數(shù)組里抗愁。

  • apply 馁蒂、call呵晚、bind三者都是用來改變函數(shù)的this對象的指向的;
    apply远搪、 call劣纲、bind 三者第一個參數(shù)都是this要指向的對象,也就是想指定的上下文谁鳍;
    apply癞季、 callbind三者都可以利用后續(xù)參數(shù)傳參倘潜;
    bind 是返回對應(yīng)函數(shù)绷柒,便于稍后調(diào)用;apply 涮因、call則是立即調(diào)用 废睦。

舉例說明:

var obj = {
    x: 81,
};
 
var foo = {
    getX: function() {
        return this.x;
    }
}
 
console.log(foo.getX.bind(obj)());  //81
console.log(foo.getX.call(obj));    //81
console.log(foo.getX.apply(obj));   //81

// 三個輸出的都是81,但是注意看使用 bind() 方法的养泡,他后面多了對括號嗜湃。
//也就是說,區(qū)別是澜掩,當你希望改變上下文環(huán)境之后并非立即執(zhí)行购披,而是回調(diào)執(zhí)行的時候,使用 bind() 方法肩榕。而 apply/call 則會立即執(zhí)行函數(shù)刚陡。

6、call stack 調(diào)用棧

"調(diào)用棧"(call stack)表示函數(shù)或子例程像堆積木一樣存放株汉,以實現(xiàn)層層調(diào)用筐乳。
舉個函數(shù)嵌套調(diào)用的例子:

function a(){
    console.log('a1')
    b.call()
    console.log('a2')
  return 'a'  
}
function b(){
    console.log('b1')
    c.call()
    console.log('b2')
    return 'b'
}
function c(){
    console.log('c')
    return 'c'
}
a.call()
console.log('end')

其執(zhí)行順序如圖所示:


下面是嵌套調(diào)用和遞歸調(diào)用時,函數(shù)的執(zhí)行順序:

7乔妈、函數(shù)中的thisarguments

(本文只介紹this和arguments是什么蝙云,暫時不介紹他們的用法,關(guān)于this更深入的認識路召,可見我的另一篇關(guān)于JS面向?qū)ο蟮牟┛?/a> 第7條)

  • 首先舉個例子:
    聲明 function fn(x,y){ return x+y }
    調(diào)用 fn.call( undefined , 1 ,2 )
    其中 贮懈,undefined 指的就是函數(shù)fn的this ,即优训,thiscall()的第一個參數(shù)朵你。1,2 指的就是函數(shù)的arguments,需要注意的一點是:arguments是一個類數(shù)組對象揣非。

  • 注意:在普通模式下抡医,this是undefined時,瀏覽器會將其變?yōu)?code>window
    在嚴格模式下,thisundefined 忌傻,打印出來的就是undefined
    大脉。

  • 舉例:

// 普通模式下:
function f(){
    console.log(this)
}
f.call(1)  // Number {1}

// 嚴格模式下:
function f(){
    'use strict'
    console.log(this)
}
f.call(1)  // 1

即,普通模式下水孩,瀏覽器會把this 轉(zhuǎn)化為對象镰矿,嚴格模式下會禁止這樣的轉(zhuǎn)換

  • 注意this必須是對象俘种,或者這么說秤标,this就是函數(shù)與對象之間的羈絆
    舉個例子:fn.call(10)宙刘,意思是想讓函數(shù)fnthis是數(shù)字10苍姜,但實際上
    JS會將其變成一個數(shù)字對象,即Number(10)悬包。

8衙猪、詞法作用域(也叫靜態(tài)作用域)

作用域(scope)指的是變量存在的范圍。在 ES5 的規(guī)范中布近,Javascript 只有兩種作用域:一種是全局作用域垫释,變量在整個程序中一直存在,所有地方都可以讀瘸徘啤棵譬;另一種是函數(shù)作用域,變量只在函數(shù)內(nèi)部存在季蚂。ES6 又新增了塊級作用域。

規(guī)則:
按照抽象語法樹琅束,就近原則
注意:我們只能確定變量是哪個變量扭屁,但是不能確定變量的值

在判斷作用域時,還要注意函數(shù)作用域內(nèi)部會產(chǎn)生的“變量提升”現(xiàn)象涩禀。var命令聲明的變量料滥,不管在什么位置,變量聲明都會被提升到函數(shù)體的頭部艾船。

9葵腹、什么是閉包

(本節(jié)只介紹閉包的概念,暫不深入屿岂,這里提供方方的一篇介紹閉包的文章用于深入了解践宴,或可見我寫的一篇關(guān)于前端基礎(chǔ)知識十題中的第四題)

如果一個函數(shù)使用了它范圍外的變量,那么(這個函數(shù)和這個變量)就叫做閉包爷怀。

閉包(closure)是 Javascript 語言的一個難點阻肩,也是它的特色,很多高級應(yīng)用都要依靠閉包實現(xiàn)运授。
理解閉包烤惊,首先必須理解變量作用域乔煞。前面提到,JavaScript 有兩種作用域:全局作用域和函數(shù)作用域柒室。函數(shù)內(nèi)部可以直接讀取全局變量渡贾。

10、柯里化

柯里化是一個聽起來很高大上的概念雄右,但也很好理解空骚。簡單來說就是一個返回函數(shù)的函數(shù),然后將函數(shù)的參數(shù)中的一個或幾個參數(shù)確定下來不脯,如將 f(x,y) 變成 f(x=1)(y) 或 f(y=1)x府怯,柯里化可以將真實計算拖延到最后再做。這里貼兩個詳細介紹柯里化的文章:http://www.yinwang.org/blog-cn/2013/04/02/currying 防楷、https://zhuanlan.zhihu.com/p/31271179

  • 舉兩個例子:
  // 第一個例子:
  // 柯里化之前
  function sum(x,y){
      return x+y
  }
  // 柯里化之后
  function addOne(y){
      return sum(1, y)
  }

  // 第二個例子:
  // 柯里化之前
  function Handlebar(template, data){
      return template.replace('{{name}}', data.name)
  }
  // 柯里化之后
  function Handlebar(template){
      return function(data){
          return template.replace('{{name}}', data.name)
      }
  }

上面的代碼中牺丙,第一個例子好理解,我們來看第二個例子复局。
柯里化之前冲簿,我們要調(diào)用函數(shù)Handlebar,每次都要傳一個template模板亿昏,比如Handlebar('<h1>I'm {{name}}</h1>',{name:'noch'}) 峦剔,如果這個一個模板(即參數(shù)template'<h1>I'm {{name}}</h1>') 我們需要用到很多次,難道每次調(diào)用都要賦一次值嗎角钩?為了簡化函數(shù)Handlebar的這種情況下的調(diào)用吝沫,我們就對該函數(shù)進行了柯里化。之后再使用時递礼,首先這么調(diào)用var newHandlebar= Handlebar('<h1>I'm {{name}}</h1>') 惨险,相當于給template賦了值,然后調(diào)用函數(shù)newHandlebarnewHandlebar({name:'enoch'}) 即可

  • 一道關(guān)于柯里化的題目:
    請寫出一個柯里化其他函數(shù)的函數(shù) curry脊髓,這個函數(shù)能夠?qū)⒔邮芏鄠€參數(shù)的函數(shù)辫愉,變成多個接受一個參數(shù)的函數(shù),具體見示例(這是 lodash.curry 的文檔示例):
function curry(???){
    ???
    return ???
}
var abc = function(a, b, c) {
  return [a, b, c];
};

var curried = curry(abc);

curried(1)(2)(3);
// => [1, 2, 3]

curried(1, 2)(3);
// => [1, 2, 3]

curried(1, 2, 3);
// => [1, 2, 3]

答案如下:

function curry(func , fixedParams){
    if ( !Array.isArray(fixedParams) ) { fixedParams = [ ] }
    return function(){
        let newParams = Array.prototype.slice.call(arguments); // 新傳的所有參數(shù)
        if ( (fixedParams.length+newParams.length) < func.length ) {
            return curry(func , fixedParams.concat(newParams));
        }else{
            return func.apply(undefined, fixedParams.concat(newParams));
        }
    };
}

11将硝、高階函數(shù)

  • 在數(shù)學和計算機科學中恭朗,高階函數(shù)是至少滿足下列一個條件的函數(shù)(也就是說至少滿足下列一個條件的函數(shù)就被稱為高階函數(shù)):
    • 接受一個或多個函數(shù)作為輸入:如:forEachsort依疼、 map痰腮、 filterreduce
    • 輸出一個函數(shù):如:bind 律罢、lodash.curry
    • 不過它也可以同時滿足兩個條件:如:Function.prototype.bind
  • 那么高階函數(shù)有什么用呢:最重要的一條就是可以將函數(shù)任意的組合诽嘉。(如react中的很多應(yīng)用)

12、回調(diào)(callback

  • 名詞形式:被當做參數(shù)的函數(shù)就是回調(diào)
  • 動詞形式:調(diào)用這個回調(diào)
  • 舉個例子:
    fn(function(){}) :函數(shù)fn中的參數(shù)是一個函數(shù),在fn中調(diào)用了這個函數(shù)虫腋,那么這個函數(shù)就是回調(diào)函數(shù)骄酗,調(diào)用的過程就是回調(diào)
  • 注意:回調(diào)跟異步?jīng)]有任何關(guān)系

13悦冀、構(gòu)造函數(shù)

簡單的來說返回對象的函數(shù)就是構(gòu)造函數(shù) 趋翻。(具體用法可看我的一篇介紹面向?qū)ο蟮牟┛?/a> 第五條)。

比如new Number() 得到的就是一個數(shù)值對象盒蟆,一般的踏烙,構(gòu)造函數(shù)的函數(shù)名首字母要大寫

再舉個栗子历等,我們自己寫一個構(gòu)造函數(shù)讨惩。

function Person(){} // 這就是個構(gòu)造函數(shù),何以見得寒屯,就要看你如何調(diào)用
var person1 = Person() // 這么寫的話荐捻,函數(shù)Person什么也沒有返回
var person2 = new Person() //使用new,函數(shù)Person中默認會多出幾行寡夹,其中就包括會返回一個空對象

// 如果想在函數(shù)中添加屬性处面,可以使用this,即:
function Person(){
  this.name = ''
  return this // 這一行可以不用寫
}
var person3 = new Person({}) // 這么調(diào)用即可菩掏,會為傳入的空對象增加一個name的屬性

14魂角、箭頭函數(shù)

箭頭函數(shù)的形式在本文第2條已經(jīng)介紹,這里不再贅述智绸。接下來主要介紹一下箭頭函數(shù)和普通的函數(shù)的區(qū)別:

  • 箭頭函數(shù)沒有this野揪,對,這就是它們之間唯一的區(qū)別瞧栗。具體的說就是:箭頭函數(shù)中如果使用了this斯稳,此時this就是相當于一個普通的參數(shù),由于箭頭函數(shù)本身沒有this沼溜,那么他就會找它的父級中的this來確定this的值平挑。
  • 舉個例子:
setTimeout(function(){
    console.log(this)
}.bind({name:'enoch'}),1000)
// 一秒后打印出 {name: "enoch"}
// 如果沒有用bind綁定this 游添,打印出的是window對象
setTimeout(function(){
    console.log(this) // A
    setTimeout(function(){
        console.log(this) // B
    },1000)
}.bind({name:'enoch'}),1000)
// 第一秒打印出 {name: "enoch"}系草,第二秒打印出window對象

第二個代碼塊中:setTimeout中又有一個setTimeout,兩個setTimeout都會執(zhí)行打印this這句話唆涝,而A處的this和B處的this顯然不是一個值(A處的this{name: "enoch"}找都,B處的 thiswindow對象)。
如果你想讓兩個this都是{name: "enoch"}廊酣,可以這么做能耻,里面的函數(shù)也用bind綁定外面的this

setTimeout(function(){
    console.log(this) // A
    setTimeout(function(){
        console.log(this) // B
    }.bind(this),1000)
}.bind({name:'enoch'}),1000)

或者使用箭頭函數(shù)

setTimeout(function(){
    console.log(this) // A
    setTimeout(()=>{
        console.log(this) // B
    },1000)
}.bind({name:'enoch'}),1000)

那么如果我硬要用call來指定箭頭函數(shù)的this可以嘛,答案是否定的,請看代碼:

var fn = ()=>{console.log(this)}
fn() // 此時打印出的是window對象
fn.call({name:'enoch'}) 
// 此時打印出來的還是window對象晓猛,箭頭函數(shù)沒有接收你指定的this

所以使用箭頭函數(shù)可以很容易的做到函數(shù)里面的this就是外面的this饿幅,不用擔心函數(shù)的this會莫名的改變。

15戒职、一些易錯的坑

看了這么多概念栗恩,覺得函數(shù)貌似也不太難呢?嘿嘿洪燥,那么請繼續(xù)磕秤,下面將寫一些函數(shù)中易錯的坑。

  • 題目1:求f1.call()的結(jié)果
var a = 1
function f1(){
    alert(a) // 是多少
    var a = 2
}
f1.call()
  • 題目2:
var a = 1
function f1(){
   var a = 2
   f2.call()
}
function f2(){
   console.log(a) // 是多少
}
f1.call()
  • 題目3:點擊第3個 li 時捧韵,打印 2 還是打印 6市咆?
var liTags = document.querySelectorAll('li')
for(var i = 0; i<liTags.length; i++){
    liTags[i].onclick = function(){
        console.log(i) // 點擊第3個 li 時,打印 2 還是打印 6再来?
    }
}
  • 題目4:這兩個代碼塊的結(jié)果一樣嗎蒙兰?
function f(){
    console.log(this)
}
f.call(1)
function f(){
    'use strict'
    console.log(this)
}
f.call(1)
  • 題目5:下面的幾個代碼塊,a的值分別為什么
var a = console.log(1);
function f(){
    return 1
}
a = f
function f(){
    return 1
}
var a = f.call()
  • 題目6:下面的幾個代碼塊其弊,a的值分別為什么
var a = 1,2
var a = (1,2)
var a = (1, console.log(2))
  • 題目7:
function f(){
    return function f2(){}
}
var a = f.call()
function f(){
    return function f2(){}
}
var a = f.call()
var b = a.call()
function f(){
    return function f2(){}
}
var a = f.call().call()
  • 題目8:
function f1(){
    console.log(this)
    function f2(){

    }
}
var obj = {name: 'obj'}
f1.call( obj )
function f1(){

    function f2(){
        console.log(this)
    }
    f2.call()
}
var obj = {name: 'obj'}
f1.call( obj )
  • 題目9:
function f1(){
    console.log(this) // 第一個 this
    function f2(){
        console.log(this) // 第二個 this
    }
    f2.call()
}
var obj = {name: 'obj'}
f1.call( obj )
為什么兩個 this 值不一樣癞己?

本題答案:
=>每個函數(shù)都有自己的 this,為什么會一樣梭伐?
=>this 就是 call 的第一個參數(shù)痹雅,第一個 this 對應(yīng)的 call 是 f1.call(obj),第二個 this 對應(yīng)的 call 是 f2.call()
=>this 和 arguments 都是參數(shù)糊识,參數(shù)都要在函數(shù)執(zhí)行(call)的時候才能確定

  • 序言:七十年代末绩社,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子赂苗,更是在濱河造成了極大的恐慌愉耙,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拌滋,死亡現(xiàn)場離奇詭異朴沿,居然都是意外死亡,警方通過查閱死者的電腦和手機败砂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門赌渣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昌犹,你說我怎么就攤上這事坚芜。” “怎么了斜姥?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵鸿竖,是天一觀的道長沧竟。 經(jīng)常有香客問我,道長缚忧,這世上最難降的妖魔是什么悟泵? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮闪水,結(jié)果婚禮上魁袜,老公的妹妹穿的比我還像新娘。我一直安慰自己敦第,他們只是感情好峰弹,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芜果,像睡著了一般鞠呈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上右钾,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天蚁吝,我揣著相機與錄音,去河邊找鬼舀射。 笑死窘茁,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的脆烟。 我是一名探鬼主播山林,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼邢羔!你這毒婦竟也來了驼抹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤拜鹤,失蹤者是張志新(化名)和其女友劉穎框冀,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敏簿,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡明也,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惯裕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片温数。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖轻猖,靈堂內(nèi)的尸體忽然破棺而出帆吻,到底是詐尸還是另有隱情域那,我是刑警寧澤咙边,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布猜煮,位于F島的核電站,受9級特大地震影響败许,放射性物質(zhì)發(fā)生泄漏王带。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一市殷、第九天 我趴在偏房一處隱蔽的房頂上張望愕撰。 院中可真熱鬧,春花似錦醋寝、人聲如沸搞挣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽囱桨。三九已至,卻和暖如春嗅绰,著一層夾襖步出監(jiān)牢的瞬間舍肠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工窘面, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留翠语,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓财边,卻偏偏與公主長得像肌括,于是被迫代替她去往敵國和親度气。 傳聞我的和親對象是個殘疾皇子喇辽,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容