JavaScript對象創(chuàng)建的七種方式詳解
前言
作為一名前端開發(fā)者,JavaScript中對象創(chuàng)建是很重要。在JavaScript這門基于原型的語言中,對象幾乎無處不在。今天,我將帶領(lǐng)大家回顧JavaScript對象創(chuàng)建的7種方式,從最原始的字面量到現(xiàn)代的ES6 class,每一步演進(jìn)都解決了前一步的痛點(diǎn),這就像是JavaScript語言設(shè)計(jì)的進(jìn)化史。
1. 對象字面量:最原始的創(chuàng)建方式
代碼示例
// 使用字面量進(jìn)行創(chuàng)建
// 通過字面量創(chuàng)建的對象,都會有原型開銷,并且他們的原型都是指向Object.prototype
var Sheep = {
name: "小羊",
school: "青青草原",
age: 18
}
// 驗(yàn)證原型鏈
const sheepPrototype = Object.getPrototypeOf(Sheep)
console.log(sheepPrototype === Object.prototype) // 輸出: true
深入講解
最初接觸JavaScript時(shí),對象字面量是我學(xué)會的第一種創(chuàng)建對象的方式。它的創(chuàng)建方式很直觀,你需要什么屬性就直接寫什么屬性。
原型鏈解析:
// 深入理解字面量對象的原型
const myObj = { a: 1 }
console.log(myObj.__proto__ === Object.prototype) // true
console.log(myObj.hasOwnProperty('a')) // true - 來自O(shè)bject.prototype
console.log(myObj.toString()) // "[object Object]" - 來自O(shè)bject.prototype
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 語法簡潔直觀,易于理解和使用
- 適合創(chuàng)建單個(gè)、獨(dú)特的對象
- 創(chuàng)建速度快,無需額外的函數(shù)調(diào)用
缺點(diǎn):
- 無法實(shí)現(xiàn)代碼復(fù)用,每個(gè)對象都需要重新定義
- 不適合創(chuàng)建大量相似的對象
- 缺乏封裝性,所有屬性都是公開的
特點(diǎn):
對象字面量就像是"手工定制",每個(gè)對象都是獨(dú)一無二的藝術(shù)品。但當(dāng)我需要創(chuàng)建100只羊時(shí),難道要寫100次相同的代碼嗎?這讓我意識到,我們需要一種"批量生產(chǎn)"的方式。
2. 工廠模式:批量生產(chǎn)的開始
代碼示例
// 使用工廠模式創(chuàng)建對象 - 避免了new關(guān)鍵字,并且具有封裝性
function Sheep(name, age) {
if (name === '喜羊羊') {
return {
name,
age,
feature: ['聰明'],
eat: function() {
console.log(`${this.name}在吃青草`)
}
}
} else {
return {
name,
age,
feature: ['貪吃鬼'],
eat: function() {
console.log(`${this.name}在吃零食`)
}
}
}
}
const sheep1 = Sheep('喜羊羊', 3)
const sheep2 = Sheep('懶羊羊', 4)
// 類型檢測問題
console.log(sheep1 instanceof Object); // true (所有對象都是Object的實(shí)例)
console.log(sheep1 instanceof Sheep); // false! 無法識別具體類型
深入講解
工廠模式是我第一次體會到"函數(shù)即工廠"的概念。把它想象成一個(gè)制造羊的工廠,你告訴工廠想要什么樣的(參數(shù)),工廠就給你制造出來(返回對象)。這種模式能夠根據(jù)不同的輸入條件,創(chuàng)建不同特性的對象。
方法重復(fù)問題演示:
function createSheep(name) {
return {
name: name,
eat: function() { // 每次調(diào)用都創(chuàng)建新函數(shù)
console.log('吃草')
}
}
}
const s1 = createSheep('羊1')
const s2 = createSheep('羊2')
console.log(s1.eat === s2.eat) // false - 方法沒有復(fù)用!
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 解決了代碼復(fù)用問題,可以批量創(chuàng)建對象
- 可以根據(jù)參數(shù)動態(tài)決定對象的屬性
- 隱藏了對象創(chuàng)建的細(xì)節(jié),提供了一定的封裝性
缺點(diǎn):
- 無法識別對象的具體類型(都是Object的實(shí)例)
- 每個(gè)對象都包含相同的方法副本,造成內(nèi)存浪費(fèi)
- 沒有利用原型鏈,無法實(shí)現(xiàn)真正的繼承
核心特點(diǎn)與反思
工廠模式就像一個(gè)"代工廠",能批量生產(chǎn)但產(chǎn)品上沒有品牌標(biāo)識。我開始思考:如何讓創(chuàng)建的對象能夠被識別出"出身"?這就引出了構(gòu)造函數(shù)的概念。
3. 構(gòu)造函數(shù)模式:引入類型標(biāo)識
代碼示例
// 使用構(gòu)造函數(shù)創(chuàng)建對象 - 使用new的好處是模板化、高效率、類型識別和封裝
// 在構(gòu)造函數(shù)中創(chuàng)建的方法在每次創(chuàng)建對象的時(shí)候,都會重新創(chuàng)建一次方法
function Sheep(name, age) {
this.name = name;
this.age = age;
this.eat = function() {
console.log(`${age}歲的${name}在吃草`)
}
}
const sheep1 = new Sheep('喜羊羊', 3)
const sheep2 = new Sheep('沸羊羊', 4)
// 類型識別成功
console.log(sheep1 instanceof Sheep) // true
console.log(sheep1.constructor === Sheep) // true
// 但方法依然沒有復(fù)用
console.log(sheep1.eat === sheep2.eat) // false - 每個(gè)實(shí)例都有獨(dú)立的eat方法
深入講解
構(gòu)造函數(shù)讓我第一次感受到JavaScript中"類"的概念(雖然ES6之前沒有真正的類)。通過new關(guān)鍵字,仿佛在說:“請按照這個(gè)藍(lán)圖(構(gòu)造函數(shù))給我制造一個(gè)對象”。new操作符背后發(fā)生了什么?
new操作符的內(nèi)部機(jī)制:
// new操作符的模擬實(shí)現(xiàn)
function myNew(Constructor, ...args) {
// 1. 創(chuàng)建一個(gè)新對象
const obj = {}
// 2. 將新對象的原型指向構(gòu)造函數(shù)的prototype
obj.__proto__ = Constructor.prototype
// 3. 將構(gòu)造函數(shù)的this綁定到新對象上并執(zhí)行
const result = Constructor.apply(obj, args)
// 4. 如果構(gòu)造函數(shù)返回對象,則返回該對象;否則返回新創(chuàng)建的對象
return result instanceof Object ? result : obj
}
// 使用示例
const mySheep = myNew(Sheep, '美羊羊', 3)
console.log(mySheep instanceof Sheep) // true
解決方法重復(fù)的嘗試:
// 解決辦法:將方法綁定到構(gòu)造函數(shù)的原型上
function Sheep(name, age) {
this.name = name;
this.age = age;
}
Sheep.prototype.eat = function() {
console.log(`${this.age}歲的${this.name}在吃草`)
}
const sheep1 = new Sheep('喜羊羊', 3)
const sheep2 = new Sheep('沸羊羊', 4)
console.log(sheep1.eat === sheep2.eat) // true - 方法復(fù)用成功!
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 解決了對象類型識別問題(instanceof可以正確判斷)
- 代碼結(jié)構(gòu)更清晰,符合面向?qū)ο蟮乃季S
- 可以通過prototype添加共享方法
缺點(diǎn):
- 方法定義在構(gòu)造函數(shù)內(nèi)部時(shí),每個(gè)實(shí)例都會創(chuàng)建方法的副本
- 內(nèi)存利用率低,相同的方法被重復(fù)創(chuàng)建
核心特點(diǎn)與反思
構(gòu)造函數(shù)就像給產(chǎn)品打上了"品牌標(biāo)簽",但每個(gè)產(chǎn)品都自帶了一套完整的"使用說明書"(方法),這顯然是一種浪費(fèi)。需要找到一種方式,讓所有同類產(chǎn)品共享同一份"說明書"。
4. 原型模式:共享的力量
代碼示例
// 原型模式 - 所有屬性和方法都定義在原型上
function Sheep() {}
// 所有屬性和方法都定義在原型上
Sheep.prototype.name = '陽光中學(xué)';
Sheep.prototype.age = 3;
Sheep.prototype.feature = ['聰明'] // 引用類型屬性
Sheep.prototype.eat = function() {
console.log('我正在吃青春蛋糕~');
};
const sheep1 = new Sheep()
const sheep2 = new Sheep()
// 方法共享成功
console.log(sheep1.eat === sheep2.eat) // true
// 但引用類型屬性共享帶來了問題
sheep1.feature.push('玩游戲')
console.log(sheep2.feature) // ['聰明', '玩游戲'] - 意外修改了所有實(shí)例!
深入講解
原型模式讓我真正理解了JavaScript的精髓:原型鏈。把原型想象成一個(gè)"公共倉庫",所有實(shí)例都可以從這個(gè)倉庫中獲取方法和屬性。這就像一個(gè)家族的"傳家寶",所有家族成員都能使用,但不能據(jù)為己有。
原型鏈查找機(jī)制:
// 深入理解原型鏈查找
const s = new Sheep()
// 屬性查找順序演示
console.log(s.hasOwnProperty('name')) // false - name不是實(shí)例自有屬性
console.log('name' in s) // true - 但能通過原型鏈找到
// 原型鏈:s -> Sheep.prototype -> Object.prototype -> null
console.log(s.__proto__ === Sheep.prototype) // true
console.log(Sheep.prototype.__proto__ === Object.prototype) // true
console.log(Object.prototype.__proto__ === null) // true
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 完美解決了方法共享問題,內(nèi)存利用率高
- 原型鏈機(jī)制支持屬性和方法的查找
- 所有實(shí)例共享原型上的屬性和方法
缺點(diǎn):
- 引用類型的屬性被所有實(shí)例共享,容易造成意外修改
- 無法在創(chuàng)建實(shí)例時(shí)傳遞初始化參數(shù)
- 所有實(shí)例的屬性初始值都相同
核心特點(diǎn)與反思
純原型模式就像"共產(chǎn)主義",所有資源都是共享的。有些東西(比如個(gè)人名字)應(yīng)該是私有的,有些東西(比如吃飯的方法)可以是共享的。這讓我意識到,我需要一種"混合經(jīng)濟(jì)體制"。
5. 組合模式:完美的平衡
代碼示例
// 組合模式(構(gòu)造函數(shù)+原型) - ES6 class出現(xiàn)之前的最佳實(shí)踐
// 獨(dú)立屬性+通用方法
function Sheep(name, age) {
// 實(shí)例屬性 - 每個(gè)實(shí)例獨(dú)有
this.name = name;
this.age = age;
this.friends = []; // 引用類型也是獨(dú)有的
}
// 共享方法 - 定義在原型上
Sheep.prototype.eat = function() {
console.log(`${this.age}歲的${this.name}在吃草`)
}
Sheep.prototype.addFriend = function(friendName) {
this.friends.push(friendName)
}
const sheep1 = new Sheep('喜羊羊', 3)
const sheep2 = new Sheep('沸羊羊', 4)
// 驗(yàn)證方法共享
console.log(sheep1.eat === sheep2.eat) // true
// 驗(yàn)證屬性獨(dú)立
sheep1.addFriend('美羊羊')
console.log(sheep1.friends) // ['美羊羊']
console.log(sheep2.friends) // [] - 不受影響
深入講解
組合模式是最優(yōu)雅的解決方案(在ES6之前)。它采用了"各司其職"的策略:構(gòu)造函數(shù)負(fù)責(zé)定義實(shí)例屬性(每個(gè)對象的"個(gè)性"),原型負(fù)責(zé)定義方法(所有對象的"共性")。這就像現(xiàn)代社會的分工合作,效率最高。
深入理解組合模式的優(yōu)勢:
// 組合模式的靈活性展示
function Animal(type) {
this.type = type;
this.energy = 100;
}
// 可以動態(tài)添加原型方法
Animal.prototype.sleep = function() {
this.energy += 20;
console.log(`${this.type}睡覺后,能量恢復(fù)到${this.energy}`)
}
// 可以覆蓋原型方法
Animal.prototype.toString = function() {
return `[Animal: ${this.type}]`
}
const cat = new Animal('貓')
console.log(cat.toString()) // [Animal: 貓]
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 完美解決了共享和獨(dú)立的平衡問題
- 每個(gè)實(shí)例有自己的屬性副本,方法則共享
- 支持向構(gòu)造函數(shù)傳遞參數(shù)
- 是ES6 class出現(xiàn)之前的最佳實(shí)踐
缺點(diǎn):
- 需要分別管理構(gòu)造函數(shù)和原型
- 代碼分散在兩個(gè)地方,不夠聚合
核心特點(diǎn)與反思
組合模式讓我理解了"取長補(bǔ)短"的智慧。它就像一個(gè)成熟的企業(yè):有私有財(cái)產(chǎn)(實(shí)例屬性),也有公共設(shè)施(原型方法)。但我還在想,有沒有更靈活的方式來控制對象的創(chuàng)建和繼承?
6. Object.create():精確控制原型鏈
代碼示例
// Object.create() - 可以顯式指定原型對象
// 示例1:顯式指定原型
const Sheep = {
name: '喜羊羊',
eat: function() {
console.log('我愛吃飯')
}
}
const sheep = Object.create(Sheep)
sheep.name = '懶羊羊' // 覆蓋原型上的name
console.log(sheep.name) // 懶羊羊
console.log(Object.getPrototypeOf(sheep) === Sheep); // true
// 示例2:創(chuàng)建無原型對象 - Object.prototype也不繼承
const sheep1 = Object.create(null);
const sheep2 = {};
// 檢查原型
console.log(Object.getPrototypeOf(sheep1)); // null
console.log(Object.getPrototypeOf(sheep2)); // [Object: null prototype] {} (即Object.prototype)
// 嘗試調(diào)用基礎(chǔ)方法
console.log(typeof sheep1.toString); // "undefined"
console.log(typeof sheep2.toString); // "function"
// 示例3:實(shí)現(xiàn)對象的淺克隆,保持原型鏈不變
function shallowClone(original) {
const clone = Object.create(Object.getPrototypeOf(original));
Object.assign(clone, original);
return clone;
}
// 克隆無原型對象
const sheep1 = Object.create(null);
sheep1.name = '喜羊羊';
const clonedSheep1 = shallowClone(sheep1);
console.log(clonedSheep1.name); // 喜羊羊
console.log(clonedSheep1 === sheep1); // false
console.log(Object.getPrototypeOf(clonedSheep1)); // null
console.log(typeof clonedSheep1.toString); // undefined
// 克隆標(biāo)準(zhǔn)對象
const sheep2 = {};
sheep2.name = '懶羊羊';
const clonedSheep2 = shallowClone(sheep2);
console.log(clonedSheep2.name); // 懶羊羊
console.log(clonedSheep2 === sheep2); // false - 是一個(gè)全新的、獨(dú)立的對象
console.log(Object.getPrototypeOf(clonedSheep2) === Object.prototype); // true
console.log(typeof clonedSheep2.toString); // function
深入講解
Object.create()對原型鏈的"完全掌控"。能夠精確地指定一個(gè)對象的原型,甚至可以創(chuàng)建一個(gè)"無根之木"(沒有原型的對象)。
Object.create()的高級用法:
// 使用第二個(gè)參數(shù)定義屬性描述符
const sheepPrototype = { eat: function() { console.log('吃草') } }
const animal = Object.create(sheepPrototype, {
age: {
value: 3,
writable: true,
enumerable: true,
configurable: true
},
id: {
value: Math.random(),
writable: false, // 只讀屬性
enumerable: false // 不可枚舉
}
})
console.log(animal.age) // 3
animal.age = 4 // 可以修改
console.log(animal.age) // 4
animal.id = 999 // 嘗試修改只讀屬性
console.log(animal.id) // 仍然是原來的隨機(jī)數(shù)
// 枚舉測試
for(let key in animal) {
console.log(key) // 只會打印age和原型上的屬性,不會打印id
}
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 提供了對原型鏈的精確控制
- 可以創(chuàng)建真正的"純凈"對象(無原型)
- 支持屬性描述符,可以定義只讀、不可枚舉等特性
- 是實(shí)現(xiàn)繼承的底層機(jī)制
缺點(diǎn):
- 語法相對復(fù)雜,不夠直觀
- 需要手動設(shè)置構(gòu)造函數(shù)
- 對于簡單場景來說過于底層
核心特點(diǎn)與反思
Object.create()就像是對象創(chuàng)建的"原子操作",它讓我看到了JavaScript對象系統(tǒng)的底層機(jī)制。但對于日常開發(fā),希望有更簡潔、更符合傳統(tǒng)OOP思維的語法。
7. ES6 Class:現(xiàn)代化的語法糖
代碼示例
// ES6 Class - class中定義的方法,不是綁定到構(gòu)造函數(shù)本身,
// 而是被自動添加到了構(gòu)造函數(shù)的prototype(原型)對象上
class Sheep {
constructor(name, age) {
// 實(shí)例屬性
this.name = name;
this.age = age;
this.friends = [];
}
// 實(shí)例方法 - 自動添加到prototype
sayHello() {
console.log(`Hello, my name is ${this.name}`);
}
eat() {
console.log(`${this.name}在吃草`);
}
addFriend(friend) {
this.friends.push(friend);
}
// 靜態(tài)方法
static compare(sheep1, sheep2) {
return sheep1.age - sheep2.age;
}
// getter
get info() {
return `${this.name} (${this.age}歲)`;
}
// setter
set info(value) {
[this.name, this.age] = value.split(',');
}
}
// 使用
const sheep1 = new Sheep('喜羊羊', 3);
const sheep2 = new Sheep('美羊羊', 2);
// 驗(yàn)證方法共享
console.log(sheep1.sayHello === sheep2.sayHello); // true
// 使用靜態(tài)方法
console.log(Sheep.compare(sheep1, sheep2)); // 1
// 使用getter/setter
console.log(sheep1.info); // 喜羊羊 (3歲)
sheep1.info = '懶羊羊,5';
console.log(sheep1.name); // 懶羊羊
console.log(sheep1.age); // "5"
深入講解
ES6 Class它本質(zhì)上還是基于原型的,但語法上更接近傳統(tǒng)的面向?qū)ο笳Z言。把它理解為一個(gè)"語法糖",背后還是我們熟悉的原型機(jī)制。
Class本質(zhì)的揭示:
// Class本質(zhì)上還是函數(shù)
console.log(typeof Sheep) // "function"
// Class定義的方法在prototype上
console.log(Sheep.prototype.sayHello) // [Function: sayHello]
// 用傳統(tǒng)方式實(shí)現(xiàn)同樣的效果
function TraditionalSheep(name, age) {
this.name = name;
this.age = age;
}
TraditionalSheep.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
};
// 驗(yàn)證:方法不屬于實(shí)例的自有屬性,而是在prototype上
const sheep = new Sheep("喜羊羊", 2)
console.log(sheep.hasOwnProperty('sayHello')); // false
console.log(sheep.__proto__.hasOwnProperty('sayHello')); // true
Class的高級特性:
// 繼承
class SmartSheep extends Sheep {
constructor(name, age, iq) {
super(name, age); // 調(diào)用父類構(gòu)造函數(shù)
this.iq = iq;
}
// 方法重寫
eat() {
super.eat(); // 調(diào)用父類方法
console.log('...一邊吃一邊思考');
}
// 新方法
solve() {
console.log(`${this.name}解決了問題!`);
}
}
const smartSheep = new SmartSheep('喜羊羊', 3, 150);
smartSheep.eat();
// 喜羊羊在吃草
// ...一邊吃一邊思考
優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 語法清晰、簡潔、易于理解
- 更好的代碼組織,所有相關(guān)代碼在一個(gè)地方
- 原生支持繼承、靜態(tài)方法、getter/setter
- 符合其他編程語言的OOP習(xí)慣
缺點(diǎn):
- 本質(zhì)還是原型,可能給其他語言背景的開發(fā)者造成誤解
- 不支持私有屬性(雖然有提案)
- 必須使用new調(diào)用(不像普通函數(shù)那樣靈活)
核心特點(diǎn)與反思
ES6 Class就像給JavaScript穿上了一件"現(xiàn)代化的外衣",讓它看起來更像Java或C++。這件外衣下面,還是JavaScript獨(dú)特的原型鏈機(jī)制。理解這一點(diǎn),對深入掌握J(rèn)avaScript至關(guān)重要。
總結(jié):7種方式的橫向?qū)Ρ?/h2>
| 創(chuàng)建方式 | 代碼復(fù)用 | 類型識別 | 內(nèi)存效率 | 參數(shù)傳遞 | 繼承支持 | 語法復(fù)雜度 | 適用場景 |
|---|---|---|---|---|---|---|---|
| 對象字面量 | ? | ? | ? | ? | ? | 簡單 | 創(chuàng)建單個(gè)對象 |
| 工廠模式 | ? | ? | ? | ? | ? | 簡單 | 批量創(chuàng)建相似對象 |
| 構(gòu)造函數(shù) | ? | ? | ? | ? | 部分 | 中等 | 需要類型識別的場景 |
| 原型模式 | ? | ? | ? | ? | ? | 中等 | 方法共享為主的場景 |
| 組合模式 | ? | ? | ? | ? | ? | 中等 | ES5最佳實(shí)踐 |
| Object.create | ? | 部分 | ? | 部分 | ? | 復(fù)雜 | 需要精確控制原型鏈 |
| ES6 Class | ? | ? | ? | ? | ? | 簡單 | 現(xiàn)代JavaScript開發(fā) |
通過這7種對象創(chuàng)建方式的學(xué)習(xí),深刻理解了JavaScript語言設(shè)計(jì)的演進(jìn)。每一種方式都有其存在的價(jià)值和適用場景。作為開發(fā)者,我們不應(yīng)該盲目追求"最新"或"最好",而應(yīng)該根據(jù)實(shí)際需求選擇最合適的方案。
以上就是JavaScript對象創(chuàng)建的七種方式詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript對象創(chuàng)建方式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Javascript中innerHTML用法實(shí)例分析
這篇文章主要介紹了Javascript中innerHTML用法,實(shí)例分析了實(shí)用innerHTML獲取對應(yīng)元素內(nèi)容的使用技巧,需要的朋友可以參考下2015-01-01
JS正則表達(dá)式詳解及身份證號碼驗(yàn)證(簡易版)
在做用戶實(shí)名驗(yàn)證時(shí),常會用到身份證號碼的正則表達(dá)式及校驗(yàn)方案,下面這篇文章主要給大家介紹了關(guān)于JS正則表達(dá)式及身份證號碼驗(yàn)證的相關(guān)資料,需要的朋友可以參考下2022-07-07
selenium 反爬蟲之跳過淘寶滑塊驗(yàn)證功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了selenium 反爬蟲之跳過淘寶滑塊驗(yàn)證功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
js獲取html參數(shù)及向swf傳遞參數(shù)應(yīng)用介紹
HTML頁面是在客戶端執(zhí)行的,這樣要獲取參數(shù)必須使用客戶端腳本如JavaScript,在這點(diǎn)上與服務(wù)器端腳本獲取參數(shù)方式有所不同接下來將詳細(xì)介紹下感興趣的你可不要錯(cuò)過了哈2013-02-02
extjs圖表繪制之條形圖實(shí)現(xiàn)方法分析
這篇文章主要介紹了extjs圖表繪制之條形圖實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了extjs繪制條形圖的相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下2020-03-03
微信小程序地圖(map)組件點(diǎn)擊(tap)獲取經(jīng)緯度的方法
這篇文章主要介紹了微信小程序地圖(map)組件點(diǎn)擊(tap)獲取經(jīng)緯度的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01

