前端面試題及答案,JS方面的


1.1、請解釋一下什么是閉包

當函數可以記住並訪問所在的作用域時,就產生了閉包,即使函數是在當前作用域之外執行。閉包有如下特性:

a. JavaScript允許你使用在當前函數以外定義的變量

b. 即使外部函數已經返回,當前函數仍然可以引用在外部函數所定義的變量

c. 閉包可以更新外部變量的值

d. 用閉包模擬私有方法

由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題。

在定時器、事件監聽器、Ajax請求、跨窗口通信、Web Workers或者任何其他的異步(或者同步)任務中,只要使用了回調函數,實際上就是在使用閉包! 

1.2call apply 的區別是什么?

call 和 apply 就是為了改變函數體內部 this 的指向。

區別是從第二個參數起,call 需要把參數按順序傳遞進去,而 apply 則是把參數放在數組里。

當參數明確時用call與apply都行, 當參數不明確時可用apply給合arguments

 

1.3、如何使用原生 Javascript 代碼深度克隆一個對象(注意區分對象類型)

用遞歸的方式克隆

function deepClone(obj)

{

  var o,i,j,k;

  if(typeof(obj)!="object" || obj===null)return obj;

  if(obj instanceof(Array))

  {

    o=[];

    i=0;j=obj.length;

    for(;i<j;i++)

    {

      if(typeof(obj[i])=="object" && obj[i]!=null)

      {

        o[i]=arguments.callee(obj[i]);

      }

      else

      {

        o[i]=obj[i];

      }

    }

  }

  else

  {

    o={};

    for(i in obj)

    {

      if(typeof(obj[i])=="object" && obj[i]!=null)

      {

        o[i]=arguments.callee(obj[i]);

      }

      else

      {

        o[i]=obj[i];

      }

    }

  }

  return o;

}

var scheduleClone = deepClone(schedule)

scheduleClone.data[0].contactList.phone[0] = 99999999999

console.log('方法1 深度克隆')

console.log(scheduleClone)

console.log(JSON.stringify(schedule))

console.log(JSON.stringify(scheduleClone))

 

用js原生的json序列化的方式

var scheduleClone2 = JSON.parse(JSON.stringify(schedule));

console.log(scheduleClone2)

scheduleClone2.data[0].contactList.phone[0] = 8888888

console.log(JSON.stringify(schedule))

console.log(JSON.stringify(scheduleClone2))

 

1.4 jQuery $(′.class′)$('div.class') 哪個效率更高?

jQuery內部使用Sizzle引擎,處理各種選擇器。Sizzle引擎的選擇順序是從右到左,所以這條語句是先選.class,

第二個會直接過濾出div標簽,而第一個就不會過濾了,將所有相關標簽都列出。

 

1.5、實現輸出document對象中所有成員的名稱和類型

for(o in document){

           type = Object.prototype.toString.call(document[o]);

           if(type =='[object Function]'){

                 console.log(o+":"+typeof o)

           }

}  

 

1.6、獲得一個DOM元素的絕對位置

offsetTop:返回當前元素相對於其 offsetParent 元素的頂部的距離

offsetLeft:返回當前元素相對於其 offsetParent 元素的左邊的距離

getBoundingClientRect():返回值是一個DOMRect對象,它包含了一組用於描述邊框的只讀屬性——left、top、right和bottom,屬性單位為像素

1.7、如何利用JS生成一個table

首先是用createElement創建一個table,再用setAttribute設置table的屬性,

然后用for循環設置tr和td的內容,用appendChild拼接內容,設置td的時候還用到innerHTMLstyle.padding。

var row, cell,

     table = document.createElement("table");

     table.setAttribute("border", 1);

     for (var i = 0; i < 10; i++) {

         row = document.createElement("tr");

         table.appendChild(row);

         for (var j = 0; j < 10; j++) {

             cell = document.createElement("td");

             cell.style.padding = "10px";

             cell.innerHTML = "單元格內容";

             row.appendChild(cell);

         }

     };

     table.appendChild(row);

     document.body.appendChild(table); 

 

1.8、實現預加載一張圖片,加載完成后顯示在網頁中並設定其高度為50px,寬度為50px

   

   var img = new Image();

      img.src = "1.jpg";

      img.onload = function() {

        img.height = 50;

        img.width = 50;

      }

      document.body.appendChild(img);

 

1.9、假設有一個4trtable,將table里面tr順序顛倒

先是通過table.tBodies[0].rows獲取到當前tbody中的行,接下來是兩種方法處理。獲取到的行沒有reverse這個方法。

1.第一種是將這些行push到另外一個數組中

var tableTemple=document.querySelector("#tableTemple");

var table_rows=tableTemple.tBodies[0].rows;

var newAry=[];

     for(var i=0;i<table_rows.length;i++){

           newAry.unshift(table_rows[i]);

     };

     for(i in newAry){

           tableTemple.tBodies[0].appendChild(newAry[i]);

     }

 

2.第二種是用Array.prototype.slice.call()將那些行變成數組,接着用reverse倒敘,table再appendChild。

 var tableTemple=document.querySelector("#tableTemple");

var table_rows=tableTemple.tBodies[0].rows;

var trs = Array.prototype.slice.call(table_rows, 0);Array.prototype.slice.call(arguments)//能將具有length屬性的對象轉成數組

    trs.reverse();

     for(var i=0;i<trs.length;i++){

           tableTemple.tBodies[0].appendChild(trs[i]);

     }

 

1.10、模擬一個HashTable類,一個類上注冊四個方法:包含有addremovecontainslength方法

先是在構造函數中定義一個數組,然后用push模擬add,splice模擬remove。

四個方法都放在了prototype上面。

function HashTable(){

           this.value=[];

     };

     HashTable.prototype.add=function(val){

           this.value.push(val);

     };

     HashTable.prototype.remove=function(index){

           this.value.splice(index,1)

     }

     HashTable.prototype.contains=function(val){

           var aValue=this.value;

           for(i in aValue){

                if(val==aValue[i]){

                      return true;

                }

           }

           return false;

     }

     HashTable.prototype.length = function() {

         return this.value.length;

     }

 

 

1.11Ajax讀取一個XML文檔並進行解析的實例

a. 初始化一個HTTP請求,IE以ActiveX對象引入。 后來標准瀏覽器提供了XMLHttpRequest類,它支持ActiveX對象所提供的方法和屬性

b. 發送請求,可以調用HTTP請求類的open()和send()方法

c. 處理服務器的響應,通過http_request.onreadystatechange = nameOfTheFunction。來指定函數

//創建請求對象

function create() {

  if (window.XMLHttpRequest) { // Mozilla, Safari, ...

      http_request = new XMLHttpRequest();

  } else if (window.ActiveXObject) { // IE

      http_request = new ActiveXObject("Microsoft.XMLHTTP");

  }

  return http_request;

}

//發起請求

function makeRequest(url) {

  http_request = create();

  http_request.onreadystatechange = alertContents;

  http_request.open('GET', url, true);

  http_request.send(null);

}

//響應函數

function alertContents() {

   if (http_request.readyState == 4) {

      if (http_request.status == 200) {

          var xmldoc = http_request.responseXML;

          var root_node = xmldoc.getElementsByTagName('root').item(0);

          alert(root_node.firstChild.data);

      } else {

         alert('There was a problem with the request.');

      }

   }

} 

 

1.12JS如何實現面向對象和繼承機制?

創建對象方法:

a. 利用json創建對象

b. 使用JavaScript中的Object類型

c. 通過創建函數來生成對象

繼承機制:

a. 構造函數綁定,使用call或apply方法,將父對象的構造函數綁定在子對象上

b. prototype模式,繼承new函數的模式

c. 直接繼承函數的prototype屬性,對b的一種改進

d. 利用空對象作為中介

e. 在ECMAScript5中定義了一個新方法Object.create(),用於創建一個新方法

f. 拷貝繼承,把父對象的所有屬性和方法,拷貝進子對象,實現繼承。

 

1.13JS模塊的封裝方法,比如怎樣實現私有變量,不能直接賦值,只能通過公有方法

a. 通過json生成對象的原始模式,多寫幾個就會非常麻煩,也不能反映出它們是同一個原型對象的實例

b. 原始模式的改進,可以寫一個函數,解決代碼重復的問題。同樣不能反映出它們是同一個原型對象的實例

c. 構造函數模式,就是一個普通函數,不過內部使用了this變量,但是存在一個浪費內存的問題。

d. Prototype模式,每一個構造函數都有一個prototype屬性,指向另一個對象。這個對象的所有屬性和方法,都會被構造函數的實例繼承,可以把那些不變的屬性和方法,直接定義在prototype對象上。Prototype模式的驗證方法:isPrototypeOf()hasOwnProperty()in運算符。

//通過json生成對象的原始模式

var cat1 = {}; // 創建一個空對象

cat1.name = "大毛"; // 按照原型對象的屬性賦值

cat1.color = "黃色";

var cat2 = {};

cat2.name = "二毛";

cat2.color = "黑色";

 

//原始模式的改進

function Cat2(name,color){

  return {

    name:name,

    color:color

  }

}

 

//構造函數模式

function Cat3(name,color){

  this.name=name;

  this.color=color;

}

 

//Prototype模式

function Cat4(name,color){

  this.name = name;

  this.color = color;

}

Cat4.prototype.type = "貓科動物";

Cat4.prototype.eat = function(){alert("吃老鼠")};

 

//Prototype驗證方法

var human = function() {}

var socrates = Object.create(human);

console.log(human.isPrototypeOf(socrates)); //=> true

//console.log(socrates.prototype.isPrototypeOf(human));

console.log(socrates instanceof human); //=> false

//console.log(socrates.prototype) 

 

1.14、對this指針的理解,可以列舉幾種使用情況?

this實際上是在函數被調用時發生的綁定,它指向什么完全取決於函數在哪里被調用。

this指的是:調用函數的那個對象。

a. 純粹的函數調用,屬於全局性調用,因此this就代表全局對象Global。

b. 作為對象方法的調用,這時this就指這個上級對象。

c. 作為構造函數調用,就是通過這個函數new一個新對象(object)。這時,this就指這個新對象。

d. applycall的調用,它們的作用是改變函數的調用對象,它的第一個參數就表示改變后的調用這個函數的對象。

//a. 純粹的函數調用

function test1() {

  this.x = 1;

  console.log(this.x);

}

test1(); // 1

 

var y = 1;

 

function test2() {

  console.log(this.y);

}

test2(); // 1

 

var z = 1;

 

function test3() {

  this.z = 2;

}

test3();

console.log(z); //2

 

//b. 作為對象方法的調用

function test4() {

  console.log(this.x);

}

var o = {};

o.x = 10;

o.m = test4;

o.m(); // 10

 

//c.作為構造函數調用

function test5() {

  this.x = 1;

}

var o = new test5();

console.log(o.x); // 1

 

//d.apply與call的調用

var x = 0;

 

function test6() {    

  console.log(this.x);  

}  

var o = {};  

o.x = 1;  

o.m = test6;  

o.m.apply(o); //1 

 

1.15、在JavaScript中,常用的綁定事件的方法有哪些?

a. 在DOM元素中直接綁定,DOM元素,可以理解為HTML標簽,onXXX="JavaScript Code"。

b. 在JavaScript代碼中綁定,elementObject.onXXX=function(){},通稱為DOM0事件系統。

c. 綁定事件監聽函數,標准瀏覽器使用 addEventListener() ,IE11以下版本attachEvent() 來綁定事件監聽函數,通稱為DOM2事件系統。

1.16、解釋下javascript的冒泡和捕獲

<div id="click1">

  <div id="click2">

     <div id="click3">事件</div>

  </div>

</div>

a. Netscape主張元素1的事件首先發生,這種事件發生順序被稱為捕獲型

b. 微軟則保持元素3具有優先權,這種事件順序被稱為冒泡型

c. W3C選擇了一個擇中的方案。任何發生在w3c事件模型中的事件,首是進入捕獲階段,直到達到目標元素,再進入冒泡階段

事件監聽函數addEventListener()的第三個參數就是控制方法是捕獲還是冒泡

    click1 = document.getElementById("click1");

     click2 = document.getElementById("click2");

     click3 = document.getElementById("click3");

     click1.addEventListener("click", returnTarget, false);

     click2.addEventListener("click", returnTarget, false);

     click3.addEventListener("click", returnTarget, false);

     function returnTarget(event) {

       console.log(event.currentTarget.id);

       //event.stopPropagation();

     }

 

1.17jQuery的特點

a. 一款輕量級的js庫

b. 豐富快速的DOM選擇器

c. 鏈式表達式

d. 事件、樣式、動畫等特效支持

e. Ajax操作封裝,支持跨域

f. 跨瀏覽器兼容

g. 插件擴展開發

 

1.18Ajax有哪些好處和弊端?

優點:

a. 無刷新更新數據

b. 異步與服務器通信

c. 前端和后端負載平衡

d. 基於標准被廣泛支持

e. 界面與應用分離

缺點:

a. AJAX干掉了Back和History功能,即對瀏覽器機制的破壞

b. AJAX的安全問題

c. 對搜索引擎支持較弱

d. 違背URL和資源定位的初衷

參考《AJAX工作原理及其優缺點

 

1.19nullundefined的區別?

null

a. null是一個表示"無"的對象,轉為數值時為0

b. null表示"沒有對象",即該處不應該有值。

undefined

a. undefined是一個表示"無"的原始值,轉為數值時為NaN。

b. undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義。

 

1.20new操作符具體干了什么呢?

a. 一個新對象被創建。它繼承自函數原型

b. 構造函數被執行。執行的時候,相應的傳參會被傳入

c. 上下文(this)會被指定為這個新實例

d. 如果構造函數返回了一個“對象”,那么這個對象會取代整個new出來的結果

 

1.21js延遲加載的方式有哪些?

a. 將script節點放置在最后</body>之前

b. 使用script標簽的defer和async屬性,defer屬性為延遲加載,是在頁面渲染完成之后再進行加載的,而async屬性則是和文檔並行加載

c. 通過監聽onload事件,動態添加script節點

d. 通過ajax下載js腳本,動態添加script節點

1.22、如何解決跨域問題?

a. JSONP(JSON with Padding),填充式JSON

b. iframe跨域

c. HTML5的window.postMessage方法跨域

d. 通過設置img的src屬性,進行跨域請求

e. 跨域資源共享(CORS),服務器設置Access-Control-Allow-OriginHTTP響應頭之后,瀏覽器將會允許跨域請求

 

1.23documen.write innerHTML的區別

write

a. 改變 HTML 輸出流

b. 當在文檔加載之后使用 document.write(),這會覆蓋該文檔。例如onload事件中

c. 輸入css的style標簽能改變樣式,例如document.write("<style>b{color:red;font-weight:bold;}</style>");

innerHTML

a. 改變 HTML 內容

b. 輸入cssstyle標簽不能改變樣式。也是能改變樣式的

 

1.24、哪些操作會造成內存泄漏?

a. 當頁面中元素被移除或替換時,若元素綁定的事件仍沒被移除,在IE中不會作出恰當處理,此時要先手工移除事件,不然會存在內存泄露。

b. 在IE中,如果循環引用中的任何對象是 DOM 節點或者 ActiveX 對象,垃圾收集系統則不會處理。

c. 閉包可以維持函數內局部變量,使其得不到釋放。

d. 在銷毀對象的時候,要遍歷屬性中屬性,依次刪除,否則會泄漏。

 

1.25JavaScript中的變量聲明提升?

函數聲明和變量聲明總是被JavaScript解釋器隱式地提升到包含他們的作用域的最頂端。

function優先聲明於var。

函數表達式中只會提升名稱,函數體只有在執行到賦值語句時才會被賦值。

function foo() {

    bar();

    var x = 1;

}

function foo() {//等同於

    var x;

    bar();

    x = 1;

}

function test() {

    foo(); // TypeError "foo is not a function"

    bar(); // "this will run!"

    var foo = function () { }// 函數表達式被賦值給變量'foo'

    function bar() { }// 名為'bar'的函數聲明

}

 

1.26、如何判斷當前腳本運行在瀏覽器還是node環境中?

通過判斷Global對象是否為window,如果是window,當前腳本運行在瀏覽器中

 

1.27、什么是 "use strict"

ECMAscript 5添加了第二種運行模式:"嚴格模式"(strict mode)

設立"嚴格模式"的目的,主要有以下幾個:

a. 消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為;

b. 消除代碼運行的一些不安全之處,保證代碼運行的安全;

c. 提高編譯器效率,增加運行速度;

d. 為未來新版本的Javascript做好鋪墊。

注:經過測試IE6,7,8,9均不支持嚴格模式

 

1.28eval是做什么的?

eval()函數可計算某個字符串,並執行其中的的 JavaScript 代碼。

eval()是一個頂級函數並且跟任何對象無關。

如果字符串表示了一個表達式,eval()會對表達式求值。如果參數表示了一個或多個JavaScript聲明, 那么eval()會執行聲明。

 

1.29JavaScript原型,原型鏈

原型:

a. 原型是一個對象,其他對象可以通過它實現屬性繼承。

b. 一個對象的真正原型是被對象內部的[[Prototype]]屬性(property)所持有。瀏覽器支持非標准的訪問器__proto__。

c. 在javascript中,一個對象就是任何無序鍵值對的集合,如果它不是一個主數據類型(undefined,null,boolean,number,string),那它就是一個對象。

原型鏈:

a. 因為每個對象和原型都有一個原型(注:原型也是一個對象),對象的原型指向對象的父,而父的原型又指向父的父,我們把這種通過原型層層連接起來的關系稱為原型鏈。

b. 這條鏈的末端一般總是默認的對象原型。

a.__proto__ = b;

b.__proto__ = c;

c.__proto__ = {}; //default object

{}.__proto__.__proto__; //null

 

 

1.30JQueryjQuery UI 有啥區別?

jQuery是一個js庫,主要提供的功能是選擇器,屬性修改和事件綁定等等。

jQuery UI則是在jQuery的基礎上,利用jQuery的擴展性,設計的插件。提供了一些常用的界面元素,諸如對話框、拖動行為、改變大小行為等等

 

1.31jQuery的源碼看過嗎?能不能簡單說一下它的實現原理?

jQuery給我們帶來了一個簡潔方便的編碼模型(1>創建jQuery對象;2>直接使用jQuery對象的屬性/方法/事件),

一個強悍的dom元素查找器($),插件式編程接口(jQuery.fn),以及插件初始化的”配置”對象思想

 

1.32jQuery 中如何將數組轉化為json字符串

在jQuery1.8.3中有個方法“parseJSON”,在這個方法中會做從string轉換為json。

如果當前瀏覽器支持window.JSON,那就直接調用這個對象中的方法。

如果沒有就使用( new Function( "return " + data ) )();執行代碼返回。

1.33、請寫出console.log中的內容

  var msg = 'hello';//頂級作用域window下有個變量msg

  function great(name, attr) {

     var name = 'david';

      var greating = msg + name + '!';

      var msg = '你好';

      for (var i = 0; i < 10; i++) {

          var next = msg + '你的id是' + i * 2 + i;

      }

console.log(arguments[0]);// david

console.log(arguments[1]);// undefined

console.log(greating);// undefineddavid!

console.log(next);// 你好你的id是189

 }

great('Tom')

 

1.35、請說明下下面代碼的執行過程

 var t=true;

 window.setTimeout(function(){

         t=false;

 },1000);

 while(t){

   console.log(1);

 }

 alert('end');

a. JavaScript引擎是單線程運行的,瀏覽器無論在什么時候都只且只有一個線程在運行JavaScript程序

b. setTimeout是異步線程,需要等待js引擎處理完同步代碼(while語句)之后才會執行,while語句直接是個死循環,js引擎沒有空閑,不會執行下面的alert,也不會插入setTimeout。我在chrome中執行在線代碼,最后瀏覽器是終止死循環執行alert。

c. JavaScript的工作機制是:當線程中沒有執行任何同步代碼的前提下才會執行異步代碼,setTimeout是異步代碼,所以setTimeout只能等js空閑才會執行,但死循環是永遠不會空閑的,所以setTimeout也永遠不會執行。

 

1.36、輸出今天的日期,以YYYY-MM-DD的方式,比如今天是2014926日,則輸出2014-09-26

function getCurrentDate(){

       var timeStr = '-';

       var curDate = new Date();

       var curYear =curDate.getFullYear();  //獲取完整的年份(4位,1970-????)

       var curMonth = curDate.getMonth()+1;  //獲取當前月份(0-11,0代表1月)

       var curDay = curDate.getDate();       //獲取當前日(1-31)

       var curWeekDay = curDate.getDay();    //獲取當前星期X(0-6,0代表星期天)

       var curHour = curDate.getHours();      //獲取當前小時數(0-23)

       var curMinute = curDate.getMinutes();   // 獲取當前分鍾數(0-59)

       var curSec =curDate.getSeconds();      //獲取當前秒數(0-59)

       var Current= curYear+timeStr+curMonth+timeStr+curDay+' '+curHour+':'+curMinute+':'+curSec;

          console.log(Current);

          return Current;

       }

     getCurrentDate()

1.37Javascriptcalleecaller的作用?

arguments.callee屬性包含當前正在執行的函數。

Function.caller返回一個對函數的引用,該函數調用了當前函數。

 

 

1.39JS異步編程方式有幾種?

a. 回調函數

b. 事件監聽

c. 發布訂閱

d. promise

 

1.40、請說說在JavaScript引用類型和值類型的理解

值類型:存儲在棧(stack)中的簡單數據段,也就是說,它們的值直接存儲在變量訪問的位置。即Undefined、Null、Boolean、Number 和 String。

引用類型:存儲在堆(heap)中的對象,也就是說,存儲在變量處的值是一個指針(point),指向存儲對象的內存處。即對象、數組

var a = {n:1};

var b = a; 

a.x = a = {n:2};

console.log(a.x);// --> undefined

console.log(b.x);// --> [object Object]

 

1.41、請解釋一下JavaScript中的作用域和作用域鏈

變量的作用域(scope):程序源代碼中定義這個變量的區域。

作用域鏈:是一個對象列表或鏈表,這組對象定義了這段代碼“作用域中”的變量。查找變量會從第一個對象開始查找,有則用,無則查找鏈上的下一個對象。

1.42、用例子來講事件委托過程

<input type="button" name="" id="btn" value="添加" />
    <ul id="ul1">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
</ul>
window.onload = function(){
                var oBtn = document.getElementById("btn");
                var oUl = document.getElementById("ul1");
                var aLi = oUl.getElementsByTagName('li');
                var num = 4;
                
                //事件委托,添加的子元素也有事件
                oUl.onmouseover = function(ev){
                    var ev = ev || window.event;
                    var target = ev.target || ev.srcElement;
                    if(target.nodeName.toLowerCase() == 'li'){
                        target.style.background = "red";
                    }
                    
                };
                oUl.onmouseout = function(ev){
                    var ev = ev || window.event;
                    var target = ev.target || ev.srcElement;
                    if(target.nodeName.toLowerCase() == 'li'){
                        target.style.background = "#fff";
                    }
                    
                };
                
                //添加新節點
                oBtn.onclick = function(){
                    num++;
                    var oLi = document.createElement('li');
                    oLi.innerHTML = 111*num;
                    oUl.appendChild(oLi);
                };
            }

 1.43、數組去重

方法1:ES6 Set函數

var strAry=[1, 2, 3, 4, 4];
var set = new Set(strAry);
console.log(set)//[1,2,3,4]

方法2:利用對象屬性存在的特性,如果沒有該屬性則存入新數組。

var strAry=[1, 2, 3, 4, 4];
function unique(arr) {
var obj={}
            var newArr=[]
            for (let i = 0; i < arr.length; i++) {
                if (!obj[arr[i]]) {
                    obj[arr[i]] = 1
                    newArr.push(arr[i])
                }   
            }
            return newArr
        }
console.log(unique(strAry))
 

 方法2:利用數組的indexOf下標屬性來查詢。

 
         
var strAry=[1, 2, 3, 4, 4];
function unique4(arr) {
            var newArr = []
            for (var i = 0; i < arr.length; i++) {
                if (newArr.indexOf(arr[i])===-1) {
                    newArr.push(arr[i])
                }
            }
            return newArr
 }
 console.log(unique4(strAry))

  1.44、跨域解決方案

1、 通過jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域資源共享(CORS)
7、 nginx代理跨域
8、 nodejs中間件代理跨域
9、 WebSocket協議跨域

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM