freeCodeCamp 高级javascript算法体验

参考博客:葡萄美酒夜光杯

1、验证美国有效号码(Validate US Telephone Numbers)

如果传入字符串是一个有效的美国电话号码,则返回true.
用户可以在表单中填入一个任意有效美国电话号码. 下面是一些有效号码的例子(还有下面测试时用到的一些变体写法):
555-555-5555
(555)555-5555
(555) 555-5555
555 555 5555
5555555555
1 555 555 5555
在本节中你会看见如800-692-7753
or8oo-six427676;laskdjf
这样的字符串. 你的任务就是验证前面给出的字符串是否是有效的美国电话号码. 区号是必须有的. 如果字符串中给出了国家代码, 你必须验证其是1. 如果号码有效就返回true; 否则返回false.
对你有帮助的资源:
RegExp 正则表达式

//思路:基本上,就是九个规则并起来。
/* var re1=/^[1-9]\d{9}$/g;
  var re2=/^[1-9]\d{2}-[0-9]\d{2}-[0-9]\d{3}$/g;
  var re3=/^\([1-9]\d{2}\)[0-9]\d{2}-[0-9]\d{3}$/g;
  var re4=/^\([1-9]\d{2}\)\s[0-9]\d{2}-[0-9]\d{3}$/g;
  var re5=/^[1-9]\d{2}\s[0-9]\d{2}\s[0-9]\d{3}$/g;
  var re6=/^[1]\s[0-9]\d{2}\s[0-9]\d{2}\s[0-9]\d{3}$/g;
  var re7=/^[1]\s[0-9]\d{2}-[0-9]\d{2}-[0-9]\d{3}$/;
  var re8=/^[1]\s\([0-9]\d{2}\)\s[0-9]\d{2}-[0-9]\d{3}$/;
  var re9=/^[1]\([0-9]\d{2}\)[0-9]\d{2}-[0-9]\d{3}$/;
  //telephoneCheck("5554555555");
  //telephoneCheck("555-555-5555");
  //telephoneCheck("(555)555-5555");
  //telephoneCheck("(555) 555-5555")
  //telephoneCheck("555 555 5555")
  //telephoneCheck("1 555 555 5555")
  //telephoneCheck("1 555-555-5555")
  //telephoneCheck("1 (555) 555-5555")
  //telephoneCheck("1(555)555-5555") */

function telephoneCheck(str) {
  var re=/^[1-9]\d{9}$|^[1-9]\d{2}-[0-9]\d{2}-[0-9]\d{3}$|^\([1-9]\d{2}\)[0-9]\d{2}-[0-9]\d{3}$|^\([1-9]\d{2}\)\s[0-9]\d{2}-[0-9]\d{3}$|^[1-9]\d{2}\s[0-9]\d{2}\s[0-9]\d{3}$|^[1]\s[0-9]\d{2}\s[0-9]\d{2}\s[0-9]\d{3}$|^[1]\s[0-9]\d{2}-[0-9]\d{2}-[0-9]\d{3}$|^[1]\s\([0-9]\d{2}\)\s[0-9]\d{2}-[0-9]\d{3}$|^[1]\([0-9]\d{2}\)[0-9]\d{2}-[0-9]\d{3}$/g;
  console.log(str.match(re));  
  if(str.match(re)){
    console.log('true');
    return true;
  }else{
    console.log('false');
    return false;
  }
}
telephoneCheck("555-555-5555");
2、对等差分(symmetric difference)

创建一个函数,接受两个或多个数组,返回所给数组的对等差分(symmetric difference)(△or⊕)数组.
给出两个集合 (如集合A = {1, 2, 3}和集合B = {2, 3, 4}), 而数学术语 "对等差分" 的集合就是指由所有只在两个集合其中之一的元素组成的集合(A △ B = C = {1, 4}). 对于传入的额外集合 (如D = {2, 3}), 你应该按照前面原则求前两个集合的结果与新集合的对等差分集合 (C △ D = {1, 4} △ {2, 3} = {1, 2, 3, 4}).
些对你有帮助的资源:
Array.reduce()

function sym(args) {
   var arr=[].slice.call(arguments);//转化为单个数组;
  console.log(arr);
  var temp=arr.reduce(function(prev,cur,index,array){
    var a=prev.filter(function(item){
      return cur.indexOf(item)==-1;
    });//返回前一个结果中,没有出现在下个结果中的部分(数组)
    var b=cur.filter(function(item){
      return prev.indexOf(item) < 0;
    });//返回下个参数中,未有出现在上个结果中的部分(数组)
    return a.concat(b);//通通连起来。输出为下个结果
  });
  console.log(temp);
  return temp.filter(function(item,index,array){
    return array.indexOf(item) == index;
  });
  //之前只是比较数组彼此之间的重复,数组内部本身也可能存在重复
  //现在解决遗留下来的问题。
//自身查重只需要让它本身第一次出现在原数组的位置为索引值index,就可以保留且只保留一个。
}
sym([1, 2, 3], [5, 2, 1, 4]);

思考1:关于[].slice.call(arguments, 1) 的思考
思考2:关于reduce
为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce的数组。
回调函数第一次执行时,previousValue和 currentValue的取值有两种情况,如果 initialValue 在调用 reduce 时被提供,那么第一个 previousValue 等于 initialValue ,并且currentValue 等于数组中的第一个值;如果initialValue 未被提供,那么previousValue 等于数组中的第一个值,currentValue等于数组中的第二个值。如果数组为空并且没有提供initialValue, 会抛出TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。
例子:数组求和——
var total = [0, 1, 2, 3].reduce(function(a, b) { return a + b;});// total == 6

3、零钱问题(Exact Change)

设计一个收银程序 checkCashRegister() ,其把购买价格(price)作为第一个参数 , 付款金额 (cash)作为第二个参数, 和收银机中零钱 (cid) 作为第三个参数.
cid 是一个二维数组,存着当前可用的找零.
当收银机中的钱不够找零时返回字符串 "Insufficient Funds". 如果正好则返回字符串 "Closed".
否则, 返回应找回的零钱列表,且由大到小存在二维数组中.

//可能还要翻译下。panny——1美分,nickel——5美分,dime——1角,quarter,25美分,one:1美元,...5美元,10美元,20美元,100美元。
//找钱系统在行业中,为了避免浮点数的不精确,通通采用整数计算。
function checkCashRegister (price, cash, cid) {
    // 刚刚好
    if(price==cash){
      return "No Need Back";
    }
    // 付款不足
    if (price > cash){
      return "Need More Money";
    }
    var base=100;//金额基数,采用整数计算
    var change=(cash-price)*base; //找零
    //定义一个函数,用来求零钱和。
    var getTotalMoney=function(arr){
        var totalMoney=0;
        arr.reduce(function (preV, currV, currIndex, array){
            totalMoney+=base*(preV[1]+currV[1]);
            return currV;
        });//叠代算法:求零钱之和。
        return totalMoney;
    }
    //余额不足,没法找了
    var remain = getTotalMoney(cid);
    if (remain==change){//如果零钱数等于应找数额,返回closed
        return "Closed";    
    }else if(remain < change){//没钱找了
        return "Insufficient Funds";
    };
    // 对应:1角-5角-1元-5元-10元-20元-50元-100元(以元为单位的基础上乘以面值基数:base这里为100)
    var dollar= [1, 5, 10, 25, 100, 500, 1000, 2000, 10000]; // TODO
    var pay={};//保存的key:dollar中面值索引,value:要找的此面值的个数
    var currLast=0;// 当前面值所剩余额
    var currMoney=0;//当前金钱面额(dollar中对应的值)
    for (var i=dollar.length-1;i>=0;i--){//由大到小循环
        //当前面值剩余金额
        currLast=cid[i][1]*base;      
        if (currLast<=0) { 
            continue;//当前面值的金额剩余0,跳过
        }
        //当前金额面值
        currMoney=dollar[i];
        // 在当前面值下取钱必须同时满足两个条件:
        // 1. 找零必须大于当前面值,比如找零51元,才可以从50里面取钱。
        // 2. 剩余的当前面值的总额足够,比如找4元,但我只有3张1元,就不符合取钱条件
        if(change>currMoney){//如果当前金额面值小于应找钱数
            if(change<currLast){ 
                // 找零小于当前面值剩余金额:比如找钱51元,当前50面值总额余额还有150元。
                pay[i]=Math.floor(change/currMoney);//取最大张数
                change-=currMoney*pay[i];//取完之后从应找余额中减去(张数x面值)
            }else{
                // 找零大于当前面值剩余金额,比如找零51元,我50元面额总值只有50元
                // 则将所有剩余金额找出
                pay[i]=Math.floor(currLast/currMoney);
                change-=currLast;//就直接减去当前面值剩余所有金额
            }
        }
    }//循环结束之后得到一个pay对象,里面包括了面值和对应应找的钱。
    console.log(pay);
    var res=[];
    // 组织最后需要找零的钱,作为最终返回的数组。
    var keys=Object.keys(pay);//找到pay对象
    var idx=0;
    var total=0;//应找零钱(pay)的总额
    for (var j=0; j<keys.length; j++) {
        // 需要找零的面值索引:比如100,50,20,10...等等
        idx=parseInt([keys[j]]);
        //计算该面值最后找出的零钱(公式:面值x需要找出数量 / 金钱面值基数)
        cid[idx][1]=dollar[idx]*pay[keys[j]]/base;
        res.unshift(cid[idx]);//把结果添加到数组的开头。符合由面值大到小的规律。
        total += dollar[idx]*pay[keys[j]]; 
        // 顺便计算下这里计算的结果应该和最开始需要找零的金额一致:
        // 面值x需要找出数量——返回到total结果中
    } 
    // 找到最后,所有能找的面值加起来还不够
    // 这里与最开始不同,这里是过滤掉了所有找不开的面值
    // 比如:要找0.05元,但是目前剩余一张0.01和1元的面值,依旧判定为找不开
    // 而最开始的是所有余额加起来都不够找
    if (total<change) {
        return "Insufficient Funds";
    }
    console.log(res);
    return res;
}
checkCashRegister(19.50, 20.00, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.10], ["QUARTER", 4.25], ["ONE", 90.00], ["FIVE", 55.00], ["TEN", 20.00], ["TWENTY", 60.00], ["ONE HUNDRED", 100.00]]);
4、库存更新(Inventory Update )

依照一个存着新进货物的二维数组,更新存着现有库存(在 arr1 中)的二维数组. 如果货物已存在则更新数量 . 如果没有对应货物则把其加入到数组中,更新最新的数量. 返回当前的库存数组,且按货物名称的字母顺序排列.

//思路:(1)对两个数组构建对象。然后用hasOwnProperty判断有,则累加,没有则定义这个属性并给他赋值。
//     (2)获取对象的属性名并排序:Object.keys(obj).sort(),返回的是一个数组。再重新定义这个数组并输出。
function updateInventory(arr1, arr2) {
  var oCur={};
  var oNew={};
  function arrToObj(arr,obj){
    for(var i=0;i<arr.length;i++){
      obj[arr[i][1]]=arr[i][0];
    }
  }//构造库存对象。
  arrToObj(arr1,oCur);
  arrToObj(arr2,oNew);

  //添加货物及属性
  for(i in oNew){
    console.log(oCur.hasOwnProperty(i))
    if(oCur.hasOwnProperty(i)){
      oCur[i]+=oNew[i];
    }else{
      oCur[i]=oNew[i];
    }
  }

  //属性名排序
  function objKeySort(obj) {//排序的函数
      var newkey = Object.keys(obj).sort();
    //newkey是一个排序后的属性名数组
      var newObj = {};
      for (var i = 0; i < newkey.length; i++) {
          newObj[newkey[i]] = obj[newkey[i]];
      }
      return newObj;//返回排好序的新对象
  }
  oCur=objKeySort(oCur);

  //反向编译这个对象,然后返回成最初的数组。
  var newArr=[];
  for(i in oCur){
    newArr.push([oCur[i],i]);
  }
  console.log(newArr);
  return newArr;
}

// 仓库库存示例
var curInv = [
    [21, "Bowling Ball"],
    [2, "Dirty Sock"],
    [1, "Hair Pin"],
    [5, "Microphone"]
];

var newInv = [
    [2, "Hair Pin"],
    [3, "Half-Eaten Apple"],
    [67, "Bowling Ball"],
    [7, "Toothpaste"]
];

updateInventory(curInv, newInv);
5、没有重复字符串(No repeats please)

把一个字符串中的字符重新排列生成新的字符串,返回新生成的字符串里没有连续重复字符的字符串个数.连续重复只以单个字符为准
例如, aab 应该返回 2 因为它总共有6中排列 (aab, aab, aba, aba, baa, baa), 但是只有两个 (aba and aba)没有连续重复的字符 (在本例中是 a).

function permAlone(str) {

  //创建正则
  var regex = /(.)\1+/g;

  // 转化数组
  var arr = str.split('');
  var permutations = [];
  var tmp;

  //全部相等时返回0,否则再判断没意义。
  if (str.match(regex) !== null && str.match(regex)[0] === str) return 0;

  // 创建一个swap函数来交换变量的内容。
  function swap(index1, index2) {
    tmp = arr[index1];
    arr[index1]=arr[index2];
    arr[index2]=tmp;
  }//简单地说是:ab,ba

  //使用该函数算法生成数组排列。
  function generate(int) {
    if(int === 1){//如果数组内只有一个数据,换言之只有单个字母,直接返回原数组。
      //确保加入我们创建的字符排列是个数组 
      permutations.push(arr.join(''));
    }else{
      for (var i=0; i<int;i++){
        generate(int-1);//自身调用,简而言之就是把后边自身的全排列好。
        swap(int % 2? 0 : i, int - 1);//偶数取0,否则取i
      }
    }
  }

  generate(arr.length);

  //过滤重复排列的数组。
  var filtered = permutations.filter(function(string) {
    return !string.match(regex);
  });

  //统计变量
  return filtered.length;
}
permAlone('abfdefa');
6、日期区间变得更友好(Friendly Date Ranges)

让日期区间更友好!
把常见的日期格式如:YYYY-MM-DD 转换成一种更易读的格式。
易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st 代替 1).
记住不要显示那些可以被推测出来的信息: 如果一个日期区间里结束日期与开始日期相差小于一年,则结束日期就不用写年份了;在这种情况下,如果月份开始和结束日期如果在同一个月,则结束日期月份也不用写了。
另外, 如果开始日期年份是当前年份,且结束日期与开始日期小于一年,则开始日期的年份也不用写。
例如:
包含当前年份和相同月份的时候,makeFriendlyDates(["2017-01-02", "2017-01-05"]) 应该返回 ["January 2nd","5th"]
不包含当前年份,makeFriendlyDates(["2003-08-15", "2009-09-21"]) 应该返回 ["August 15th, 2003", "September 21st, 2009"]。
请考虑清楚所有可能出现的情况,包括传入的日期区间是否合理。对于不合理的日期区间,直接返回 undefined 即可

function makeFriendlyDates(arr) {

  //定义两个对象,一个存放参数1,一个存放参数2
  var oDate1={},oDate2={};
  var reArr=[];
  for(var i=0;i<arr.length;i++){
    reArr[i]=arr[i].split('-');
    if(i==0){
        oDate1["year"]=reArr[i][0];
        oDate1["month"]=reArr[i][1];
        oDate1["day"]=reArr[i][2];
    }else{
        oDate2["year"]=reArr[i][0];
        oDate2["month"]=reArr[i][1];
        oDate2["day"]=reArr[i][2];
    }    
  }//通过这段程序把两个日期参数转化为两个json对象。格式为{"year":xxxx,"month:xx","day":xxx}(xxx全为数字)

  //因为上面的json还不足以满足格式,所以还得写个json,再写个函数转化这两个json。
  var oMonth={
    "01":"January",
    "02":"February",
    "03":"March",
    "04":"April",
    "05":"May",
    "06":"June",
    "07":"July",
    "08":"August",
    "09":"September",
    "10":"October",
    "11":"November",
    "12":"December"
  };//定义月份对象
  function getFunDay(obj){
    //判断日期:
    switch(obj["day"]){
        case "01":
            obj["day"]="1st";
            break;
        case "02":
            obj["day"]="2nd";
            break;
        case "03":
            obj["day"]="3rd";
            break;
        case "04":
        case "05":
        case "06":
        case "07":
        case "08":
        case "09":
            obj["day"]=obj["day"][1]+"th";
            break;
        case "21":
            obj["day"]+='st';
            break;
        case "22":
            obj["day"]+='nd';
            break;
        case "23":
            obj["day"]+='rd';
            break;
        default:
            obj["day"]+='th';
    }
    //判断月份
    for(i in oMonth){
        if(obj["month"]==i){
            obj["month"]=oMonth[i];
        }
    }
  }
  getFunDay(oDate1);
  getFunDay(oDate2);
  //console.log(oDate1);
  //转化之后这两个对象的格式就正确了。

  //接下来是一段非常繁琐的判断流程,如果是新手,建议画出流程图来做
  if(oDate1["year"]==oDate2["year"]){//是否同年
    if(oDate1["month"]==oDate2["month"]){//是否同年同月
        if(oDate1["day"]==oDate2["day"]){//是否同年同月同日
            console.log([[oDate1["month"],oDate1["day"]+",",oDate1["year"]].join(' ')])//注意,同年同月同日的话,这里有个全直接输出口。
            return [[oDate1["month"],oDate1["day"]+",",oDate1["year"]].join(' ')];
        }else{//同年同月不同日
          delete oDate1["year"];
          delete oDate2["year"];
          delete oDate2["month"];  
        } 
    }else{ //同年不同月   
        delete oDate2["year"];
    }
  }else if((Math.abs(oDate1["year"]-oDate2["year"])==1)){//不同年,年份但只差一年
    if(oDate1["month"]<oDate2["month"]){//如果在一年以内
        delete oDate1["year"];
        delete oDate2["year"];
    }else if(oDate1["month"]==oDate2["month"]){//差一年同月
        if(oDate1["day"]>oDate2["day"]){ //小于一年
            delete oDate2["year"];
        }
    } 
  }

  //以下定义输出函数。把json数据转化为一个字符串。
  //默认的输出格式里,日期是带逗号的,但经过上面一轮判断,日期可能变成字符串的最后一个。在带逗号就不对了。所以需要判断字符串
  function retArr(obj1,obj2){
    var returnArr=[];
    //先按输出规则构造一个数组
    //这些规则可能调用了已被删除的属性。对应为undefined。所以过滤掉。
    var objstr1=[obj1["month"],obj1["day"]+",",obj1["year"]].filter(function(a){return a!=undefined}).join(' ');
    var objstr2=[obj2["month"],obj2["day"]+",",obj2["year"]].filter(function(a){return a!=undefined}).join(' ');
    //
    if(objstr1.substring(objstr1.length-1)==','){
        
        objstr1=objstr1.replace(objstr1.substring(objstr1.length-1),'')
    }
    if(objstr2.substring(objstr2.length-1)==','){
        console.log(objstr1.substring(objstr1.length-1))
        objstr2=objstr2.replace(objstr2.substring(objstr2.length-1),'')
    }
    returnArr=[objstr1,objstr2];
    
    return returnArr;
  }
  console.log(retArr(oDate1,oDate2));
  return retArr(oDate1,oDate2);
}

makeFriendlyDates(["2016-07-01", "2016-07-04"]);
//makeFriendlyDates(["2016-12-01", "2017-02-03"]);
//makeFriendlyDates(["2016-12-01", "2018-02-03"]);
//makeFriendlyDates(["2017-03-01", "2017-05-05"]);
//makeFriendlyDates(["2018-01-13", "2018-01-13"]);
//makeFriendlyDates(["2022-09-05", "2023-09-04"]);
//makeFriendlyDates(["2022-09-05", "2023-09-05"])
7、构造一个对象(Make a Person)

用下面给定的方法构造一个对象.
方法有 getFirstName(), getLastName(), getFullName(), setFirstName(first), setLastName(last), and setFullName(firstAndLast).
所有有参数的方法只接受一个字符串参数.
所有的方法只与实体对象交互.
对你有帮助的资源:
Closures
Details of the Object Model

function Person(fullName){
    
    this.getFirstName=function(){
        return fullName.split(' ')[0];
    };
    this.getLastName=function(){
        return fullName.split(' ')[1];
    };
    this.getFullName=function(){
        return fullName;
    };

    this.setFirstName=function(firstName){
        var arr=fullName.split(' ');
        arr.splice(0,1,firstName)  
        fullName=arr.join(' ');   
    };
    this.setLastName=function(lastName){
        var arr=fullName.split(' ');
        arr.splice(1,1,lastName); 
        fullName=arr.join(' ');  
    };
    this.setFullName=function(name){
        fullName=name;
    };

}
var bob = new Person('Bob Ross');
bob.getFullName();
8、地图的碎片(Map the Debris)

返回一个数组,其内容是把原数组中对应元素的平均海拔转换成其对应的轨道周期.
原数组中会包含格式化的对象内容,像这样{name: 'name', avgAlt: avgAlt}.
至于轨道周期怎么求,戳这里 on wikipedia(不想看英文的话可以自行搜索以轨道高度计算轨道周期的公式).
求得的值应该是一个与其最接近的整数,轨道是以地球为基准的.地球半径是 6367.4447 kilometers, 地球的GM值是 398600.4418, 圆周率为Math.PI
这是一些对你有帮助的资源:
Math.pow()

//地球半径是 6367.4447 kilometers, 地球的GM值是 398600.4418, 圆周率为Math.PI
//orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]) 应该返回 [{name: "sputnik", orbitalPeriod: 86400}].
//orbitalPeriod([{name: "iss", avgAlt: 413.6}, {name: "hubble", avgAlt: 556.7}, {name: "moon", avgAlt: 378632.553}]) 应该返回 [{name : "iss", orbitalPeriod: 5557}, {name: "hubble", orbitalPeriod: 5734}, {name: "moon", orbitalPeriod: 2377399}].
function orbitalPeriod(arr) {
  var GM = 398600.4418;
  var earthRadius = 6367.4447;
  return arr;
}
orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);
//在此需要补下高一物理的课。以万有引力做向心力,则GMm/R^2=mrω^2 ω=2π/T,R=r+h,所以T=2π(r+h)·sqr((r+h)/GM)。

function orbitalPeriod(arr) { 
  var GM = 398600.4418;
  var earthRadius = 6367.4447;
  for(var i=0;i<arr.length;i++){
    var R=(arr[i].avgAlt+6367.4447);
    var T=R*2*Math.PI*Math.sqrt((R/GM));
    delete arr[i].avgAlt;
    arr[i].orbitalPeriod=Math.round(T);
  }
  console.log(arr)
  return arr;
}
orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]);
9、找到你的另一半(Pairwise)

找到你的另一半
都说优秀的程序员擅长面向对象编程,但却经常找不到另一半,这是为什么呢?因为你总是把自己局限成为一个程序员,没有打开自己的思维。
这是一个社群的时代啊,在这里你应该找到与你有相同价值观但又互补的另一半。
譬如:你编程能力强,估值11分,如果以20分为最佳情侣来计算,你应该找一个设计能力强,估值为9分的女生。
那么当你遇到一个设计能力为9分的女生,千万别犹豫,大胆去表白。千万别以为后面的瓜比前面的甜哦。
举个例子:有一个能力数组[7,9,11,13,15],按照最佳组合值为20来计算,只有7+13和9+11两种组合。而7在数组的索引为0,13在数组的索引为3,9在数组的索引为1,11在数组的索引为2。
所以我们说函数:pairwise([7,9,11,13,15],20) 的返回值应该是0+3+1+2的和,即6。
我们可以通过表格来更直观地查看数组中索引和值的关系:
Index 0 1 2 3 4
Value 7 9 11 13 15

//思路:原题意思是匹配了一次之后数组项就不能再用了。那就把它设为false吧。
function pairwise(arr, arg) {
  var arr2=arr;
  var count=0;
  for(var j=0;j<arr.length;j++){
    for(var i=j+1;i<arr2.length;i++){
        if(arr[j]+arr2[i]==arg){
          count+=i+j;
          arr[i]="false";
          arr[j]="false"
        }      
    }
  }
    console.log(count);
    return count;  
}

PS:暂时参照别人的博客整理运行了一下,还没有单个的做详细的研究,欢迎大家留言私信交流O(∩_∩)O

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

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,204评论 0 4
  • 第1章 认识JS JavaScript能做什么?1.增强页面动态效果(如:下拉菜单、图片轮播、信息滚动等)2.实现...
    mo默22阅读 1,238评论 0 5
  • 一、JS前言 (1)认识JS 也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HT...
    凛0_0阅读 2,752评论 0 8
  • 满眼望去,尽是银装素裹;微微抬头,雪花融入眼帘;在这样的时节里,江明尘一洗俗世尘气,带着如冰雪般透明的馨儿向水云山...
    任风寻阅读 232评论 2 2
  • 1.cap n帽子,v戴上帽子 n队员,v使选国家队 n上限,v限定开支 n盖子,v覆盖 2.cape n岬角 n...
    轩0211阅读 1,731评论 0 3