前端知識體系總結(jié)

數(shù)據(jù)結(jié)構(gòu)與算法


棧和隊列的區(qū)別

網(wǎng)絡基礎


HTTP 無狀態(tài)怎么理解

可以從REST的角度來理解這個問題。我們知道REST風格是無狀態(tài)的。而REST是基于HTTP協(xié)議的,所以REST的無狀態(tài)基本就可以解釋HTTP的無狀態(tài)。

TCP三次握手與四次揮手

三次握手
為了準確無誤地將數(shù)據(jù)送到目標處,TCP采用三次握手策略,過程中使用了TCP的標志:SYN和ACK.
三次握手
Client --> 置SYN標志 序列號 = J,確認號 = 0 ----> Server
Client <-- 置SYN標志 置ACK標志 序列號 = K, 確認號 = J + 1 <-- Server
Clinet --> 置ACK標志 序列號 = J + 1,確認號 = K + 1 --> Server
四次揮手
Client -> 發(fā)送FIN 序列號 = J,確認號 = 0 --> Server
Server -> 發(fā)送ACK 確認號 = J + 1
Server -> 發(fā)送FIN 序列號 = K, 確認號 = 0 -> Client
Client -> 發(fā)送ACK 確認號 = K+1

HTTPS

HTTPS是在HTTP與TCP之間添加一個安全協(xié)議層(SSL或TSL).
網(wǎng)絡請求中往往中間需要很多服務器或者路由器的轉(zhuǎn)發(fā),中間的節(jié)點都可能篡改信息,而如果使用HTTPS,密鑰在請求客戶端和終點站才有,所以相對于HTTP會更安全,就是因為HTTPs利用SSL/TSL協(xié)議傳輸,它包含證書等安全信息,保證了傳輸過程的安全性。

前端其他問題


前端工程價值

  • 解放前后端互相在開發(fā)進度上的依賴問題,前后端可以同時進行
  • 為簡化用戶使用,提高交互體驗/用戶體驗
  • 解決瀏覽器兼容問題
  • 提高瀏覽速度(性能)
  • 跨平臺應用的支持
  • 展現(xiàn)數(shù)據(jù),數(shù)據(jù)處理
  • 降低后端壓力

瀏覽器緩存技術

** Etag **

當發(fā)送一個服務器的請求時,瀏覽器會首先進行緩存過期的判斷,瀏覽器根據(jù)緩存過期的時間判斷緩存文件是否過期。

  • 若沒有過期,則不向服務器發(fā)送請求,直接使用緩存中的結(jié)果

Session Cookie LocalStorage

全局環(huán)境與局部環(huán)境

JS對象 BOM DOM

http://www.runoob.com/jsref/dom-obj-event.html

瀏覽器的基本組成與頁面渲染原理

為什么不能頻繁操作DOM

重排與重繪

前端模塊化


https://segmentfault.com/p/1210000007731421?from=singlemessage&isappinstalled=1
CommonJs規(guī)范 - NodeJs實現(xiàn) 同步
分支 異步
AMD RequireJs
CMD SeaJs
UMD 前后端整合
ES6 - I import export

前端優(yōu)化


前端兼容性


漸進增強和優(yōu)雅降級

** 漸進增強 ** :針對低版本瀏覽器進行構(gòu)建頁面,保證最基本的功能,然后再針對高級瀏覽器進行效果、交互等改進和追加功能達到更好的用戶體驗。
** 優(yōu)雅降級 ** :一開始就構(gòu)建完整的功能,然后再針對低版本瀏覽器進行兼容。

前端安全性


常見的幾種安全攻擊

SQL 注入
XSS
CSRF

前端工具


模塊打包工具

** Webpack **

  1. 模塊打包工具
  1. 管理依賴模塊間依賴,生成優(yōu)化并且合并后的靜態(tài)資源文件
  2. 編譯輸出靜態(tài)文件,將代碼分割成不同的chunk,實現(xiàn)按需加載,降低初始化時間
  3. 所有文件都是模塊, html, js, css, 圖片等
  4. 模塊加載器, 支持串聯(lián)操作
  5. 以commonJs的形式書寫,但對AMD/CMD的支持也比較全面,方便舊項目進行代碼遷移

HTML5


Webworker

Js中的多線程實現(xiàn)

Websocket

SVG

Canvas

CSS


position的值, relative和absolute分別是相對于誰進行定位的?

盒模型

IE盒模型與其他瀏覽器的盒模型

CSS選擇器的優(yōu)先級

JavaScript


ES6

參考:http://es6.ruanyifeng.com/

Js運行機制

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

  • Javascript 是單線程
    Javascript 的單線程與它的用途有關
  • 任務隊列
    任務可分為兩種,一種是同步任務,一種是異步任務。
    ** 同步任務 :在主線程上排隊執(zhí)行的任務,只有前一個任務執(zhí)行完畢后,才能執(zhí)行后一個任務;
    ** 異步任務 :不進入主線程,而進入任務隊列(task queue)的任務,只有任務隊列通知主線程,某個異步任務要以執(zhí)行了,該任務才會進入主線程執(zhí)行。
    ** 異步任務運行機制如下:

    Paste_Image.png

    1)所有同步任務都在主線程上執(zhí)行,形成一個執(zhí)行棧(execution context stack)。
    2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結(jié)果,就在"任務隊列"之中放置一個事件。
    3)一旦"執(zhí)行棧"中的所有同步任務執(zhí)行完畢,系統(tǒng)就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,于是結(jié)束等待狀態(tài),進入執(zhí)行棧,開始執(zhí)行。
    4)主線程不斷重復上面的第三步。
    ** 只要主線程空了,就會去讀取"任務隊列",這就是JavaScript的運行機制。這個過程會不斷重復。
  • 事件和任務隊列
    ** 任務隊列 **
  1. 是一個事件的隊列,也可以理解成是消息隊列。主線程讀取任務隊列就是讀取里面有哪些事件。
  2. 任務隊列里面不止有IO設備的事件,也有用戶操作產(chǎn)生的事件。只要指定過回調(diào)函數(shù),這些事件發(fā)生時就會進入任務隊列中,等待主線程讀取。主線程執(zhí)行異步任務,就是執(zhí)行對應的回調(diào)函數(shù)。
  3. 主線程會首先檢查執(zhí)行時間,某些事件只有到了規(guī)定的時間,才能返回主線程。如setTimeout().
    ** Event Loop **
    主線程從事件隊列中讀取事件的過程是不斷循環(huán)的,所以整個的運行機制就是一個Event Loop,也叫事件循環(huán)。


    Paste_Image.png
  4. 定時器
    除了放置異步任務的事件,"任務隊列"還可以放置定時事件,即指定某些代碼在多少時間之后執(zhí)行。這叫做"定時器"(timer)功能,也就是定時執(zhí)行的代碼。
    setTimeout()
    setInterval()
    HTML5標準規(guī)定了setTimeout()的第二個參數(shù)的最小值(最短間隔),不得低于4毫秒,如果低于這個值,就會自動增加。在此之前,老版本的瀏覽器都將最短間隔設為10毫秒。另外,對于那些DOM的變動(尤其是涉及頁面重新渲染的部分),通常不會立即執(zhí)行,而是每16毫秒執(zhí)行一次。這時使用requestAnimationFrame()的效果要好于setTimeout()。
    需要注意的是,setTimeout()只是將事件插入了"任務隊列",必須等到當前代碼(執(zhí)行棧)執(zhí)行完,主線程才會去執(zhí)行它指定的回調(diào)函數(shù)。要是當前代碼耗時很長,有可能要等很久,所以并沒有辦法保證,回調(diào)函數(shù)一定會在setTimeout()指定的時間執(zhí)行。

Js事件模型

參考:https://segmentfault.com/a/1190000006934031?from=singlemessage&isappinstalled=1
DOM事件探秘

  • ** 發(fā)布訂閱模式(觀察者模式)**
    Javascript的事件模型基于發(fā)布請閱模式,可以讓多個觀察者對象同時監(jiān)聽某一個主題對象,這個主題對象的狀態(tài)變化會通知所有的訂閱者,使得它們能夠做出反應。
    以下是用js實現(xiàn)的一個發(fā)布訂閱模式
var events = (function () {
    var topics = {};
    return {
        publish: function (topic, info) {
            console.log("publish a topic:" + topic);
            if (topics.hasOwnProperty(topic)) {
                topics[topic].forEach(function(handler) {
                    handler(info ? info : {});
                });
            }
        },
        subscribe: function(topic, handler) {
            console.log("subscribe an topic" + topic);
            if (!topics.hasOwnProperty(topic)) {
                topics[topic] = [];
            }
            topics[topic].push(handler);
        },
        remove: function(topic, handler) {
            if (!topics.hasOwnProperty(topics)) {
                return;
            }
            var handlerIndex = -1;
            topics[topic].forEach(function (element, index) {
                if (element === handler) {
                    handlerIndex = index;
                }
            });
            if (handlerIndex >= 0) {
                topics[topic].splice(handlerIndex, 1);
            }
        }
    };
})();
var handler = function (info) {
    console.log(info);
}
events.subscribe("hello", handler);
events.publish("hello", "hello world");
  • ** 事件與事件流 **
    事件是與瀏覽器或文檔交互的瞬間,如點擊按鈕,填寫表格等,它是JS與HTML之間交互的橋梁。DOM是樹形結(jié)構(gòu),如果同時給父子節(jié)點都綁定事件時,當觸發(fā)子節(jié)點的時候,這兩個事件的發(fā)生順序如何決定?這就涉及到事件流的概念,它描述的是頁面中接受事件的順序。
    事件流有兩種:
    ** 事件冒泡(Event Capturing): ** 是一種從下往上的傳播方式。事件最開始由最具體的元素(文檔中嵌套層次最深的那個節(jié)點接受, 也就是DOM最低層的子節(jié)點), 然后逐漸向上傳播到最不具體的那個節(jié)點,也就是DOM中最高層的父節(jié)點。
    ** 事件捕獲(Event Bubbling): **與事件冒泡相反。事件最開始由不太具體的節(jié)點最早接受事件, 而最具體的節(jié)點最后接受事件。
  • ** 事件模型 **
    ** DOM 0級模型 **
    HTML代碼中直接綁定:
<input type="button" onclick="fun()">

通過JS代碼指定屬性值:

var btn = document.getElementById('.btn');btn.onclick = fun;

移除監(jiān)聽函數(shù):

btn.onclick = null;

這種方式所有瀏覽器都兼容,但是邏輯與顯示并沒有分離。
** IE事件模型 **
IE事件模型共有兩個過程:
事件處理階段(target phase)。事件到達目標元素, 觸發(fā)目標元素的監(jiān)聽函數(shù)。
事件冒泡階段(bubbling phase)。事件從目標元素冒泡到document, 依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件綁定監(jiān)聽函數(shù)的方式如下:

attachEvent(eventType, handler)

事件移除監(jiān)聽函數(shù)的方式如下:

detachEvent(eventType, handler)

參數(shù)說明:
eventType指定事件類型(注意加on)
handler是事件處理函數(shù)
Example:

var btn = document.getElementById('.btn');
btn.attachEvent(‘onclick’, showMessage);
btn.detachEvent(‘onclick’, showMessage);

** DOM 2級模型 **
屬于W3C標準模型,現(xiàn)代瀏覽器(除IE6-8之外的瀏覽器)都支持該模型。在該事件模型中,一次事件共有三個過程:
事件捕獲階段(capturing phase)。事件從document一直向下傳播到目標元素, 依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件處理階段(target phase)。事件到達目標元素, 觸發(fā)目標元素的監(jiān)聽函數(shù)。
事件冒泡階段(bubbling phase)。事件從目標元素冒泡到document, 依次檢查經(jīng)過的節(jié)點是否綁定了事件監(jiān)聽函數(shù),如果有則執(zhí)行。
事件綁定監(jiān)聽函數(shù)的方式如下:

addEventListener(eventType, handler, useCapture)

事件移除監(jiān)聽函數(shù)的方式如下:

removeEventListener(eventType, handler, useCapture)

Example:

var btn = document.getElementById('.btn');
btn.addEventListener(‘click’, showMessage, false);
btn.removeEventListener(‘click’, showMessage, false);

參數(shù)說明:
eventType指定事件類型(不要加on)
handler是事件處理函數(shù)
useCapture是一個boolean用于指定是否在捕獲階段進行處理,一般設置為false與IE瀏覽器保持一致。
DOM事件模型中的事件對象常用屬性:

  • type用于獲取事件類型
  • target獲取事件目標
  • stopPropagation()阻止事件冒泡
  • preventDefault()阻止事件默認行為
    IE事件模型中的事件對象常用屬性:
  • type用于獲取事件類型
  • srcElement獲取事件目標
  • cancelBubble阻止事件冒泡
  • returnValue阻止事件默認行為

Javascript垃圾回收機制

** 標記清除 ** -> 最常見的垃圾回收方式
這是JavaScript最常見的垃圾回收方式,當變量進入執(zhí)行環(huán)境的時候,比如函數(shù)中聲明一個變量,垃圾回收器將其標記為“進入環(huán)境”,當變量離開環(huán)境的時候(函數(shù)執(zhí)行結(jié)束)將其標記為“離開環(huán)境”。垃圾回收器會在運行的時候給存儲在內(nèi)存中的所有變量加上標記,然后去掉環(huán)境中的變量以及被環(huán)境中變量所引用的變量(閉包),在這些完成之后仍存在標記的就是要刪除的變量了
** 引用計數(shù) ** -> 會出現(xiàn)因為循環(huán)引用而出現(xiàn)的無法回收而導致的內(nèi)存泄漏
參考: http://www.itdecent.cn/p/80ed3805edc3

創(chuàng)建對象的幾種方式

  • ** 使用{}
var bar = {
  color: "blue"
};
  • ** 使用new關鍵字 **
var bar = new Object();
bar.color = "blue";
  • ** 使用構(gòu)造函數(shù) **
var Fun = function (color) {
  this.color = color;
}
var bar = new Fun();

面向?qū)ο笈c繼承的幾種方式

** 原型編程泛型基本規(guī)則 **

  • 所有的數(shù)據(jù)都是對象
  • 要得到一個對象,不是通過 實例化類,而是找到一個對象作為原型并克隆它
  • 對象會記住它的原型
  • 如果對象本身無法響應某個請求,它會把這個請求委托給它自己的原型
    ** 實現(xiàn)方式 **
    http://www.jb51.net/article/81766.htm

解決跨域問題

Jsonp
Cors
Document.domain
Document.name
HTML5 postMessage

AJAX

創(chuàng)建過程
(1)創(chuàng)建XMLHttpRequest對象,也就是創(chuàng)建一個異步調(diào)用對象.
(2)創(chuàng)建一個新的HTTP請求,并指定該HTTP請求的方法、URL及驗證信息.
(3)設置響應HTTP請求狀態(tài)變化的函數(shù).
(4)發(fā)送HTTP請求.
(5)獲取異步調(diào)用返回的數(shù)據(jù).(6)使用JavaScript和DOM實現(xiàn)局部刷新.
參考:https://segmentfault.com/a/1190000004322487

說說你對作用域鏈的理解

作用域鏈的作用是保證執(zhí)行環(huán)境里有權訪問的變量和函數(shù)是有序的,作用域鏈的變量只能向上訪問,變量訪問到window對象即被終止,作用域鏈向下訪問變量是不被允許的。

閉包

實現(xiàn)延遲打印1-5

for (var i = 0; i < 5; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, i * 1000)
  })(i);
}
for (var i = 0; i < 5; i++) {
  setTimeout(function (i) {
    return function() { console.log(i); };
  }(i), i * 1000)
}
[1,2,3,4,5,6].forEach(i => {
    setTimeout(function () {
      console.log(i)
    }, i * 1000);
});

嚴格模式 (use strict)

  • 非嚴格模式下有些錯誤會在運行時被悄悄地忽略掉,而在嚴格模式下,這些錯誤會被拋出來,從而方便debug,通常來說,這是一種很好的實踐。
  • 防止給未聲明的變量賦值
  • 非嚴格模式下如果引用的this是null或者undefined的話會自動將this指向global對象,這種情況會造成一些比較難發(fā)現(xiàn)且頭疼的bug。而在嚴格模式下,則會拋出錯誤。
  • 防止在一個對象內(nèi)重復定義屬性。
  • 安全使用eval()
  • delete操作符

如何判讀一個變量是個整數(shù) (實現(xiàn) isInteger(x))

在ES6中,Number.isInteger() 可以用來判斷是否為整數(shù)。
在ES6之前的版本中這個問題則比較復雜,因為numberic的值通常是作為一個浮點數(shù)來存儲的,只能用比較取巧的方式來實現(xiàn)這樣的判斷邏輯。

function isInteger(x) { return (x^0) === x; }
function isInteger(x) { return Math.round(x) === x; }
function isInteger(x) { 
  return  (typeof x === "number") && (x % 1 === 0;;
}

此外也可以使用parseInt來實現(xiàn)

function isInteger(x) { return parseInt(x, 10) === x;}

數(shù)組操作 (split, reverse, push, slice, concat)

What will the code below output to the console and why?

var arr1 = "john".split('');
var arr2 = arr1.reverse();
var arr3 = "jones".split('');
arr2.push(arr3);
console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));
console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));

JavaScript 設計模式


Angular


雙向綁定如何實現(xiàn)

臟檢查機制

React


虛擬DOM 實現(xiàn)機制

JQuery


Jquery 綁定事件的方法

target.on("click");
target.click(function() {
});
target.live("click", function () {
});
target.bind("click", function () {
});

#### Jquery的鏈式操作如何實現(xiàn)

# 正則表達式
****
#### 語法
> https://msdn.microsoft.com/zh-cn/library/ae5bf541(VS.80).aspx

#### 驗證身份證
> ```
var reg=/^[1-9]{1}[0-9]{14}$|^[1-9]{1}[0-9]{16}([0-9]|[xX])$/;

面試題


更多面試題: https://www.toptal.com/javascript/interview-questions

鼠標點擊頁面中的任意標簽,alert標簽名稱 (兼容性)

<script type="text/javascript" >
document.onClick() = function(event) {
    var e = event || window.event;
    var src = event.target || event.srcElement;
    alert(src.tagName.toLowercase());
}
</script>

異步加載js方案,不少于兩種

** 同步加載 **

就是我們平時使用的最多的方式,在頁面中使用script標簽
這種模式也叫阻塞模式,會阻止瀏覽器的后續(xù)處理,停止后續(xù)的解析,只有當加載完成,才能進行下一步的操作,所以默認同步執(zhí)行才是比較安全的。但是這種方式會造成頁面的阻塞,所以一般建議把<script>標簽放在<body>結(jié)尾,這樣盡可能減少頁面阻塞。

** 異步加載 **

異步加載 又叫非阻塞加載,瀏覽器在下載執(zhí)行js的同時,還會繼續(xù)進行后續(xù)頁面的處理。主要有以下幾中方式:

  • ** Script Dom Element **
(function() {
    var scriptEle = document.createElement("script");
    scriptEle.type = "text/javascript";
    scriptEle.async = true;
    scriptEle.src="http://xxx/jquery.js";
    var x = document.getElementByTagName("head")[0];
    x.insertBefore(scriptEle, x.firstChild);
})();

google的使用方式

(function(){;
    var ga = document.createElement('script'); 
    ga.type = 'text/javascript'; 
    ga.async = true; 
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(ga, s); 
})();

缺點: 執(zhí)行完成之前會阻止onLoad事件的觸發(fā),而現(xiàn)在很多頁面的代碼都會在onLoad的時候做一些額外的渲染動作,所以還是會阻塞部分頁面的初始化的處理。

  • ** onload時的異步加載 **
;(function () {
  if (window.attachEvent) {
    window.attachEvent('load', asyncLoad)
  } else {
    window.addEventListener('load', asyncLoad)
  }
  var asyncLoad = function () {
    var scriptEle = document.createElement('script')
    scriptEle.type = 'text/javascript'
    scriptEle.async = true
    scriptEle.src = 'http://xxx/jquery.js'
    var x = document.getElementByTagName('head')[0]
    x.insertBefore(scriptEle, x.firstChild)
  }
})()

注:DOMContentLoaded與load區(qū)別
前者是在document 已經(jīng)解析完成,頁面中的dom元素可用,但是頁面中的圖片,視頻,音頻等資源還未加載完,作用同jquery的ready. 后者的區(qū)別在于頁面中所有資源包括js都加載完成。

  • ** 其他方法**
    ** XHR Injection **
    通過XMLHttpRequest來獲取javascript,然后創(chuàng)建一個script元素插入到DOM結(jié)構(gòu)中。ajax請求成功后設置script.text為請求成功后返回的responseText
var getXmlHttp = function () {
  var obj
  if (window.XMLHttpRequest)
    obj = new XMLHttpRequest()
  else
    obj = new ActiveXObject('Microsoft.XMLHTTP')
  return obj
}
var xhr = getXmlHttp()
xhr.open('GET', 'http://xxx.com/jquery.js', true)
xhr.send()
xhr.onReadyStateChange = function () {
  if (xhr.readyState == 4 && xhr.status == 200) {
    var script = document.createElement('script')
    script.text = xhr.response.text
    document.getElementsByTagName('head')[0].appendChild(script)
  }
}

** XHR Eval **
與XHR Injection對responseText的執(zhí)行方式不同,直接把responseText放在eval()函數(shù)里面執(zhí)行。
** Script In IFrame **
在父窗口插入一個iframe元素,然后再iframe中執(zhí)行加載JS的操作。

var insertJS = function(){alert(2)};
    var iframe = document.createElement("iframe");
    document.body.appendChild(iframe);
    var doc = iframe.contentWindow.document;//獲取iframe中的window要用contentWindow屬性。
    doc.open();
    doc.write("<script>var insertJS = function(){};<\/script><body onload='insertJS()'></body>");
    doc.close();
  • ** HTML5新屬性:async和defer屬性 **
    ** defer屬性 **:IE4.0就出現(xiàn)。defer屬聲明腳本中將不會有document.write和dom修改。瀏覽器會并行下載其他有defer屬性的script。而不會阻塞頁面后續(xù)處理。注:所有的defer腳本必須保證按順序執(zhí)行的。
<script type="text/javascript" defer></script>

** async屬性 **:HTML5新屬性。腳本將在下載后盡快執(zhí)行,作用同defer,但是不能保證腳本按順序執(zhí)行。他們將在onload事件之前完成。

<script type="text/javascript" defer></script>

Firefox 3.6、Opera 10.5、IE 9和最新的Chrome和Safari都支持async屬性。可以同時使用async和defer,這樣IE 4之后的所有IE都支持異步加載。
沒有async屬性,script將立即獲?。ㄏ螺d)并執(zhí)行,期間阻塞了瀏覽器的后續(xù)處理。如果有async屬性,那么script將被異步下載并執(zhí)行,同時瀏覽器繼續(xù)后續(xù)的處理。


** 總結(jié) **: 對于支持HTML5的瀏覽器,實現(xiàn)JS的異步加載只需要在script元素中加上async屬性,為了兼容老版本的IE還需加上defer屬性;對于不支持HTML5的瀏覽器(IE可以用defer實現(xiàn)),可以采用以上幾種方法實現(xiàn)。原理基本上都是向DOM中寫入script或者通過eval函數(shù)執(zhí)行JS代碼,你可以把它放在匿名函數(shù)中執(zhí)行,也可以在onload中執(zhí)行,也可以通過XHR注入實現(xiàn),也可以創(chuàng)建一個iframe元素,然后在iframe中執(zhí)行插入JS代碼。

設計一種方案,確保頁面中所有js加載完全

function loadScript (url, callback) {
var script = document.createElement('script')
script.type = 'text/javascript'
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == 'loaded' || script.readyState == 'complete') {
script.onreadystatechange = null
callback()
}
}
} else {
script.onload = function () {
callback()
}
}
script.src = url
document.getElementsByName('head')[0].appendChild(script)
}

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容