JavaScript函數(shù)

在JavaScript中,函數(shù)即對象,程序可以隨意操控它們。比如,JavaScript可以把函數(shù)賦值給變量,或者作為參數(shù)傳遞給其他函數(shù),并且可以給它們設置屬性,甚至調用它們的方法。

函數(shù)定義

一般函數(shù)定義的形式有以下幾種:

  • 函數(shù)聲明法
function factorial(x) {
    if(x <= 1) return 1;
    return x * factorial(x - 1);
}

注意:函數(shù)聲明語句"被提前"到腳本的頂部,所以可以在定義之前的代碼調用函數(shù)。

  • 函數(shù)賦值法(可定義為匿名函數(shù))
var square = function(x) { return x*x; }

注意:變量的聲明是可以提前的,但是給變量的賦值不會提前,所以這種方式的函數(shù)在定義之前無法調用。

  • 函數(shù)定義后立即執(zhí)行
var tensquared = (function(x) { return x*x; }(10));

注意: function左邊的左括號是必需的,因為如果不寫左括號,JavaScript解釋器會將關鍵字function解析為函數(shù)聲明語句。使用左括號后,JavaScript解釋器才會正確地將其解析為函數(shù)定義表達式

  • 嵌套函數(shù)
function hypotenuse(a, b) {
    function square(x) { return x*x; }
    return Math.sqrt( square(a) + square(b) );
}

注意:嵌套函數(shù)中,注意作用域的使用。

函數(shù)調用

有4種方式可以調用JavaScript函數(shù):

  • 作為函數(shù)
  • 作為方法
  • 作為構造函數(shù)
  • 通過call()和apply()方法間接調用

作為函數(shù)調用

函數(shù)調用就是直接通過function對象來調用函數(shù)。

var probability = factorial(5) / factorial(13);

根據(jù)ECMAScript3和非嚴格的ECMAScript5的規(guī)定,函數(shù)調用的上下文(this的值)是全局對象(window)。在ECMAScript 5的嚴格模式下,調用上下文是undefined。

作為方法調用

  • 方法調用是通過對象的屬性來調用函數(shù)。
  • 方法調用和函數(shù)調用最大的一個區(qū)別是:調用上下文。方法調用的上下文是調用它的對象,可以通過this關鍵字引用該對象。
  • this是一個關鍵字,不是變量,也不是屬性名。JavaScript不允許給this賦值。
var calculator = {
    operand1: 1,
    operand2: 2,
    add: function() {
        this.result = this.operand1 + this.operand2;
    }
};

calculator.add();       // 方法調用
calculator["add"]();    // 另一種形式的方法調用
calculator.result;      // 2,對象屬性添加成功
  • 如果嵌套函數(shù)作為函數(shù)調用,則this值不是全局對象就是undefined。
var o = {
  m: function() {
    var self = this;
    console.log(this === o);            // true
    f();                                // 作為函數(shù)調用
    
    function f() {
      console.log(this === o);          // false
      console.log(this === window);     // true
    }
  }
}
  • 如果嵌套函數(shù)作為方法調用,則this值指向調用它的對象。
var o = {};
function outer() {
    var inner = function() {
        console.log(this === o);
    };
    o.m = inner;
}
outer();
o.m();          // 輸出: true,作為方法調用

作為構造函數(shù)調用

  • 如果函數(shù)或方法調用之前帶有關鍵字new,它就構成構造函數(shù)調用。
  • 構造函數(shù)調用和普通的函數(shù)調用以及方法調用在實參處理、調用上下文和返回值方面都有不同。
  • 構造函數(shù)調用會創(chuàng)建一個新的空對象,這個對象繼承自構造函數(shù)的prototype屬性。構造函數(shù)使用這個新創(chuàng)建的對象作為調用上下文,并可以使用this關鍵字引用這個新創(chuàng)建的對象。
var o = {
    m: function() {
        console.log(this === o);
    }
};


o.m();              // true,方法調用
var s = new o.m();  // false,構造函數(shù)調用

間接調用

  • JavaScript中的函數(shù)也是對象,函數(shù)對象也可以包含方法。其中的2個方法call()和apply()可以用來間接地調用函數(shù)。
  • 兩個方法允許顯式指定調用所需的this值,也就是說,任何函數(shù)可以作為任何對象的方法來調用,哪怕這個函數(shù)不是那個對象的方法。
  • 在ECMAScript3和非嚴格模式中,傳入的null和undefined都會被全局對象代替,而其他原始值則會被相應的包裝對象所替代
f.call(o);
f.apply(o);

函數(shù)的實參和形參

JavaScript中的函數(shù)定義并未指定函數(shù)形參的類型,函數(shù)調用也未對傳入的實參值做任何類型檢查。實際上,JavaScript函數(shù)調用甚至不檢查傳入形參的個數(shù)。函數(shù)對于未傳入的參數(shù)賦值為undefined,對于多余的參數(shù)忽略

可選形參

由于調用函數(shù)傳入的實參個數(shù)可以比形參個數(shù)少,所以函數(shù)應當對此有一個較好的適應性,給省略的參數(shù)賦一個合理的默認值。

function getPropertyNames(o, /* optional */ a) {
    if (a === undefined)  a = [];    // 如果未定義,則使用新數(shù)組
    
    for (var property in o) 
        a.push(property);
        
    return a;
}

var a = getPropertyNames(o);    // 將o的屬性存儲到一個新數(shù)組中
getPropertyNames(p, a);         // 將p的屬性追加到數(shù)組a中

其中第一個if判斷語句可簡寫為:

a = a || [ ];

實參對象(arguments)

  • 實參對象是一個類數(shù)組對象,可以通過數(shù)字下標訪問傳入函數(shù)的實參值,而不用非要通過形參名字來得到實參。

下面的函數(shù)可以接收任意數(shù)量的實參:

function max(/* ... */) {
    var max = Number.NEGATIVE_INFINITY;
    // 遍歷實參,查找并記住最大值
    for(var i = 0; i < arguments.length; i++) 
        if(arguments[i] > max) max = arguments[i];
    
    return max;
}
  • 在非嚴格模式下,實參對象的數(shù)組元素是函數(shù)形參所對應實參的別名,可以通過實參對象修改實參的值。
  • 在非嚴格模式下,arguments僅僅是一個標識符,在嚴格模式中,它變成了一個保留字。嚴格模式中的函數(shù)無法使用arguments作為形參名或局部變量名,也不能給arguments賦值。
function f(x) {
    console.log(x);         // 輸出實參的初始值
    arguments[0] = null;    // 修改實參數(shù)組元素同樣會修改x的值
    console.log(x);         // 輸出"null"
}

callee和caller屬性

  • 除了數(shù)組元素,實參對象還定義了callee和caller屬性。
  • callee屬性指代當前正在執(zhí)行的函數(shù)。caller指代調用當前正在執(zhí)行的函數(shù)的函數(shù)。

在匿名函數(shù)中,可通過callee來遞歸地調用自身:

var factorial = function(x) {
    if (x <= 1) return 1;
    return x * arguments.callee(x-1);
}

將對象屬性用做實參

當一個函數(shù)包含超過3個形參時,對于程序員說,要記住調用函數(shù)中實參的正確順序比較困難。最好通過名/值對的形式來傳入?yún)?shù),這樣參數(shù)的順序就無關緊要了。

function arraycopy(/* array */ from, /* array */ to, /* integer */ length) {
    // 邏輯代碼
}

// 使用對象當參數(shù)
function easycopy(args) {
    arraycopy(args.from, args.to, args.length);
}

var a = [1,2,3,4], b = [];
easycopy({ from: a, to: b, length: 4});

實參類型校驗

JavaScript會在必要的時候進行類型轉換,如果期望的實參是一個字符串,那么實參值無論是原始值還是對象都可以很容易地轉換成字符串。但是當期望的實參是一個數(shù)組時,就無法對非數(shù)組對象進行轉換了,所以有必要對實參進行校驗。

function flexisum(a) {
    var total = 0;
    for (var i=0; i < arguments.length; i++) {
        var element = arguments[i], n;
        
        if (element == null) continue;          // 忽略null和undefined實參
        if (isArray(element))
            n = flexisum.apply(this, element);  // 如果是數(shù)組,遞歸計算累加和
        else if (typeof element === "function")
            n = Number(element());              // 如果是函數(shù),調用它并做類型轉換
        else
            n = Number(element);
        
        if (isNaN(n))
            throw Error("flexisum(): can't convert" + element + " to number.");
        
        total += n;
    }
    
    return total;
}

作為值的函數(shù)

在JavaScript中,函數(shù)不僅是一種語法,也是值,也就是說,可以將函數(shù)賦值給變量,存儲在對象的屬性或數(shù)組的元素中,作為參數(shù)傳入另外一個函數(shù)等。

// 聲明一個函數(shù)
function square(x) { return x*x; }

var s = square;         // 賦值給變量
s(4);                   // => 16

var o = { m: square };  // 賦值給對象
o.m(5);                 // => 25

var a = [square, 6];    // 賦值給數(shù)組
a[0](a[1]);             // => 36

自定義函數(shù)的屬性

函數(shù)是一種特殊的對象,所以可以為函數(shù)定義屬性以完成特殊的需求。
可以通過函數(shù)屬性實現(xiàn)"靜態(tài)"變量的需求。

// 由于函數(shù)聲明被提前了,因此可以在聲明之前賦值
uniqueInteger.counter = 0;

function uniqueInteger() {
    return uniqueInteger.counter++;
}

var a = uniqueInteger();    // 0
a = uniqueInteger();        // 1
a = uniqueInteger();        // 2

作為命名空間的函數(shù)

不在任何函數(shù)內聲明的變量是全局變量,在整個JavaScript程序中都是可見的。基于這個原因,我們常常簡單地定義一個函數(shù)用做臨時的命名空間,在這個命名空間內定義的變量都不會污染到全局命名空間。

function mymodule() {
    // 這個模塊所使用的所有變量都是局部變量
    // 而不會污染全局命名空間
}

閉包

JavaScript也采用詞法作用域,也就是說,函數(shù)的執(zhí)行依賴于變量作用域,這個作用域是在函數(shù)定義時決定的,而不是調用時決定的。為了實現(xiàn)這種詞法作用域,JavaScript函數(shù)對象的內部狀態(tài)不僅包含函數(shù)的代碼邏輯,還包含函數(shù)定義時的作用域鏈。
函數(shù)體內部的變量都可以保存在函數(shù)作用域內,看起來是函數(shù)將變量"包裹"起來了,這種特性稱為"閉包"。

var scope = "global scope";
function checkscope() {
    var scope = "local scope";
    
    // 定義時使用局部變量
    function f() { return scope; }
    
    return f(); // 返回函數(shù)的調用結果
}

checkscope();   // => "local scope"

如果更改下checkscope定義,將返回值更改為函數(shù)定義,如下:

var scope = "global scope";
function checkscope() {
    var scope = "local scope";
    
    // 定義時使用局部變量
    function f() { return scope; }
    
    return f;   // 返回函數(shù)的定義
}

checkscope()();   // => "local scope"

雖然調用函數(shù)的作用域變了,但是函數(shù)的輸出結果依然不變,因為函數(shù)保存了自己的作用域鏈。
通過閉包,可以實現(xiàn)一個更好的計數(shù)器類,將變量包裹起來:

function counter() {
    var n = 0;
    return {
        count: function() { return n++; }
        reset: function() { n = 0; }
    };
}

var c = counter();
c.count();          // => 0
c.count();          // => 1
c.reset();          // => 0

函數(shù)屬性、方法和構造函數(shù)

length屬性

arguments.length表示傳入函數(shù)的實參的個數(shù)。函數(shù)的length屬性表示函數(shù)形參的個數(shù),這個屬性是只讀的。
可以通過這個屬性對函數(shù)的參數(shù)個數(shù)進行校驗:

function check(args) {
    var actual   = args.length;
    var expected = args.callee.length;  // 形參個數(shù)
    if (actual != expected) {
        throw Error("Expected " + expected + "args; got " + actual);
    }
}

prototype屬性

這個屬性指向一個對象的引用,這個對象稱做"原型對象"。每一個函數(shù)都包含不同的原型對象。當將函數(shù)用做構造函數(shù)的時候,新創(chuàng)建的對象會從原型對象上繼承屬性。

call()和apply()方法

這2個方法屬于函數(shù)的方法屬性,在前面已經(jīng)有介紹,不再重復介紹。

bind()方法

bind()是在ECMAScript5中新增的方法,這個方法的主要作用就是返回一個新的函數(shù),這個函數(shù)將bind的對象作為調用上下文

function f(y) { return this.x + y; }
var o = { x: 1 };
var g = f.bind(o);  // bind返回一個函數(shù)
g(2);               // =>1,以對象o作為調用上下文執(zhí)行f(y)

可以通過如下代碼來實現(xiàn)簡單的bind():

function bind(f, o) {
    if (f.bind) return f.bind(o);
    else return function() {
        // 此處的arguments為調用bind返回函數(shù)時傳遞的參數(shù)
        // 上例中為2(g(2))
        return f.apply(o, arguments);   
    }
}

但ECMAScript5中的bind()方法不僅僅是將函數(shù)綁定至一個對象,它還能將實參也綁定至this,這種編程技術, 有時被稱為"柯里化"(currying)。參照下面的例子:

function f(y,z) { return this.x + y + z; };
var g = f.bind({x: 1}, 2);  // 綁定this和y
g(3);                       // =>6,this.x綁定到1,y綁定到2,z綁定到3

下面的代碼給出了更標準的bind()方法,將這個方法另存為Function.prototye.bind:

if( !Function.prototye.bind) {
    Function.prototye.bind = function(o /*, args */) {
        // 將this和arguments的值保存在變量中
        // 以便在后面嵌套的函數(shù)中使用
        var self = this, boundArgs = arguments;
        
        // bind()返回一個函數(shù)
        return function() {
            // 創(chuàng)建一個實參列表,保存?zhèn)魅氲乃袑崊?            var args = [], i;
            for(i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]);
            for(i = 0; i < arguments.length; i++) args.push(arguments[i]);
            
            // 以綁定對象o作為上下文來調用函數(shù)self
            // 并傳遞所有的實參args
            return self.apply(o, args);
        };
    };
}

ECMAScript5定義的bind()方法有一些特性是上述代碼無法模擬的:

  • 真正的bind()方法返回的函數(shù),length屬性是綁定函數(shù)的形參個數(shù)減去綁定的實參個數(shù)。
  • 真正的bind()方法可以創(chuàng)建構造函數(shù),如果bind()返回的函數(shù)用做構造函數(shù),將忽略bind()傳入的this,但是實參會正常綁定。
  • 由bind()方法返回的函數(shù)并不包含prototype屬性,如果返回函數(shù)用做構造函數(shù),則創(chuàng)建的對象從原始的未綁定構造函數(shù)中繼承prototype,同時,使用instanceof運算符,綁定構造函數(shù)和未綁定構造函數(shù)并無兩樣。
function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function() { 
  return this.x + ',' + this.y; 
};

var p = new Point(1, 2);
p.toString(); // '1,2'

var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// 以下這行代碼在 polyfill 不支持,
// 在原生的bind方法運行沒問題:
//(譯注:polyfill的bind方法如果加上把bind的第一個參數(shù),即新綁定的this執(zhí)行Object()來包裝為對象,Object(null)則是{},那么也可以支持)
// var YAxisPoint = Point.bind(null, 0/*x*/);

// 綁定函數(shù)的length屬性 = 形參個數(shù) - 綁定實參個數(shù)
console.log(YAxisPoint.length);                         // =>1,(2-1)

// 綁定函數(shù)不包含prototype屬性
console.log(Point.prototype);                           // "Point { toString-function()}"
console.log(YAxisPoint.prototype);                      // undefined

// 綁定函數(shù)用做構造函數(shù)
// this指代新創(chuàng)建的對象
var axisPointA = new YAxisPoint();
console.log(axisPointA.toString());                     // '0,undefined'

var axisPoint = new YAxisPoint(5);
console.log(axisPoint.toString());                      // '0,5'

// 使用instanceof時,綁定構造函數(shù)和未綁定構造函數(shù)并無兩樣
console.log(axisPoint instanceof Point);                // true
console.log(axisPoint instanceof YAxisPoint);           // true
console.log(new Point(17, 42) instanceof YAxisPoint);   // true

toString()方法

和所有的JavaScript對象一樣,函數(shù)也有toString()方法。實際上,大多數(shù)(非全部)的toString()方法的實現(xiàn)都返回函數(shù)的完整源碼。內置函數(shù)往往返回一個類似"[native code]"的字符串。

Function()構造函數(shù)

  • 前面已經(jīng)介紹,函數(shù)可以通過定義語句或直接量表達式來定義。函數(shù)還可以通過Function()構造函數(shù)來定義。
  • Function()構造函數(shù)可以傳入任意數(shù)量的實參,最后一個實參表示的是函數(shù)體。
  • Function()構造函數(shù)并不需要通過傳入實參以指定函數(shù)名。Function()會構造一個匿名函數(shù)。
var f = new Function("x", "y", "return x*y;");

// 這個定義與下面的函數(shù)定義等價
var f = function(x, y) { return x*y; }

Function()構造函數(shù)有以下幾個特點:

  • Function()在運行時動態(tài)地創(chuàng)建并編譯函數(shù)。
  • 每次調用Function()構造函數(shù)都會解析函數(shù)體,并創(chuàng)建新的函數(shù)對象。
  • Function()構造函數(shù)創(chuàng)建的函數(shù)并不使用詞法作用域,函數(shù)體代碼的編譯總是在頂層函數(shù)執(zhí)行
var scope = "global";
function constructFunction() {
    var scope = "local";
    
    return new Function("return scope");    // 無法捕獲局部作用域
}

constructFunction()();                      // => "global"

可調用對象(callable object)

可調用對象是一個對象,可以在函數(shù)調用表達式中調用這個對象。所有的函數(shù)都是可調用的,但并非所有的可調用對象都是函數(shù)。

  • IE8之前的版本實現(xiàn)了客戶端方法(諸如window.alert()和Document.getElementsById()),使用了可調用的宿主對象,而不是內置函數(shù)對象。IE9將它們實現(xiàn)為真正的函數(shù),因此此類可調用的對象越來越罕見。
  • 另外一個常見的可調用對象是RegExp對象,但代碼最好不要對可調用的RegExp對象有太多依賴,對RegExp執(zhí)行typeof運算的結果并不統(tǒng)一,在有些瀏覽器中返回"function",在有些返回"object"。

檢測一個對象是否是真正的函數(shù)對象:

function isFunction() {
    return Object.prototye.toString.call(x) === "[object Function]";
}

函數(shù)式編程

和Lisp、Haskell不同,JavaScript并非函數(shù)式編程語言,但可以像操控對象一樣操控函數(shù),也就是說,JavaScript中可以應用函數(shù)式編程技術

使用函數(shù)處理數(shù)組

使用函數(shù)式編程,簡潔地實現(xiàn)計算平均值、標準差:

// 首先定義2個函數(shù)對象
var sum    = function(x,y) { return x+y; }
var square = function(x)   { return x*x; }

// 使用函數(shù)式編程計算平均數(shù)、標準差
var data = [1,1,3,5,5];
// 計算平均數(shù)
var mean = data.reduce(sum) / data.length;  

// 計算標準差
var deviations = data.map(function(x) { return x-mean; });
var stddev     = Math.sqrt(deviations.map(square).reduce(sum) / (data.length-1));

高階函數(shù)(higher-order function)

高階函數(shù)就是操作函數(shù)的函數(shù),它接收一個或多個函數(shù)作為參數(shù),并返回一個新函數(shù)。

function mapper(f) {
    return function(a) { return a.map(f); } // 注意: 此處沒有對參數(shù)a進行數(shù)組驗證
}

var increment   = function(x) { return x+1; }
var incrementer = mapper(increment);
incrementer([1,2,3]);   // => [2,3,4]

不完全函數(shù)(partial function)

不完全函數(shù)是一種函數(shù)變換技巧,即把一次完整的函數(shù)調用拆成多次函數(shù)調用,每次傳入的實參都是完整實參的一部分,每個拆分開的函數(shù)叫做不完全函數(shù),每次函數(shù)調用叫做不完全調用(partial application)。

// 實現(xiàn)一個工具函數(shù),將類數(shù)組對象轉換為真正的數(shù)組
function array(a, n) { return Array.prototye.slice.call(a, n || 0); }

// 將第1次調用的實參放在左側
function partialLeft(f /* , ... */ ) {
    var args = arguments;
    return function() {
        var a = array(args, 1);          // 獲取第1個參數(shù)之后所有的實參
        a = a.concat(array(arguments));
        return f.apply(this, a);
    };
}

// 將第1次調用的實參放在右側
function partialRight(f /* , ... */ ) {
    var args = arguments;
    return function() {
        var a = array(arguments);
        a = a.concat(array(args, 1));
        return f.apply(this, a);
    };
}


// 將第1次調用實參中的undefined值替換成第2次調用的實參
function partial(f /* , ... */ ) {
    var args = arguments;
    return function() {
        var a = array(args, 1);
        var i = 0, j = 0;
        for(; i < a.length; i++) {
            if(a[i] === undefined) a[i] = arguments[j++];
        }
        a = a.concat(array(arguments, j));
        return f.apply(this, a);
    };
}

// 這個函數(shù)帶有3個參數(shù)
var f = function(x, y, z) { return x * (y - z); };

partialLeft(f, 2)(3, 4);        // => -2  [2 * (3 - 4)]
partialRight(f, 2)(3, 4);       // => 6;  [3 * (4 -2)]
partial(f, undefined)(3, 4);    // => -6; [3 * (2 - 4)]

記憶(memorization)

記憶只是一種編程技巧,本質上是以空間換時間,在客戶端代碼中,執(zhí)行時間往往成為瓶頸,因此這種做法是非常可取的。
下面定義一個高階函數(shù),接收一個函數(shù)作為實參,并返回帶有記憶能力的函數(shù):

function memorize(f) {
    var cache = {};
    
    return function() {
        var key = arguments.length + Array.prototye.join.call(arguments, ",");
        if(key in cache) 
            return cache[key];
        else
            return cache[key] = f.apply(this, arguments);
    };
}

// 定義有記憶功能的斐波那契函數(shù)
var factorial = memorize(function(n) {
                            return (n <= 1) ? 1: n * factorial(n-1);
                        });
factorial(5);   // => 120,同時記憶了4~1的值
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內容