【转发】数组,字符串常用方法

心已入冬 提交于 2019-11-27 18:54:08


1. 数组对象
改变原数组的:
1.shift:将第一个元素删除并且返回删除元素,空即为undefined

var arr = ['a', 'b', 'c'];
arr.shift() // 'a'
console.log(arr) // ['b', 'c']
1
2
3
2.unshift:向数组开头添加元素,并返回新的长度

var arr = ['a', 'b', 'c'];
arr.unshift('x'); // 4
console.log(arr); // ['x', 'a', 'b', 'c']
1
2
3
3.pop:删除最后一个并返回删除的元素

var arr = [1,2,3];
console.log( arr.pop() );  // [3]  //返回删除的元素
console.log(arr); // [1,2]
1
2
3
4.push:向数组末尾添加元素,并返回新的长度

var arr = [1,2,3];
console.log(arr.push(4)); // 4 //表示当前数组长度
console.log(arr); // [1, 2, 3, 4]
1
2
3
5.reverse:颠倒数组顺序

var arr = ['a', 'b', 'c'];
arr.reverse() // ["c", "b", "a"]
console.log(arr) // ["c", "b", "a"]
1
2
3
6.sort:对数组排序

['d', 'c', 'b', 'a'].sort()
// ['a', 'b', 'c', 'd']

[4, 3, 2, 1].sort()
// [1, 2, 3, 4]

[11, 101].sort()
// [101, 11]

[10111, 1101, 111].sort()
// [10111, 1101, 111]
1
2
3
4
5
6
7
8
9
10
11
注意:上面代码的最后两个例子,sort方法不是按照大小排序,而是按照对应字符串的字典顺序排序。也就是说,数值会被先转成字符串,再按照字典顺序进行比较,所以101排在11的前面。

如果想让sort方法按照自定义方式排序,可以传入一个函数作为参数,表示按照自定义方法进行排序。该函数本身又接受两个参数,表示进行比较的两个元素。如果返回值大于0,表示第一个元素排在第二个元素后面;其他情况下,都是第一个元素排在第二个元素前面。

var arr = [10111, 1101, 111];
arr.sort(function (a, b) {
return a - b;
})
//使用箭头函数简化排序时传入的函数
arr.sort((a, b)=> {
return a - b;
})
// [111, 1101, 10111]

var arr1 = [
{ name: "张三", age: 30 },
{ name: "李四", age: 24 },
{ name: "王五", age: 28 }
]

arr1.sort(function (o1, o2) {
return o1.age - o2.age;
})
// [
// { name: "李四", age: 24 },
// { name: "王五", age: 28 },
// { name: "张三", age: 30 }
// ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
7.splice:splice(index ,howmany,item1,item2…)删,增,替换数组元素,返回被删除数组,无删除则不返回(只对数组操作,slice()可用于数组也可用于字符串,split只对字符串操作)
index 必需。规定从何处添加/删除元素。该参数是开始插入和(或)删除的数组元素的下标,必须是数字。
howmany 必需。规定应该删除多少元素。必须是数字,但可以是 “0”。如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。
item 可选。规定要添加到数组的新元素。从 index 所指的下标处开始插入。

var lang = ["php","java","javascript"];
//如果只有一个参数,则删除从 index 开始到原数组结尾的所有元素
alert(lang.splice(1));//java,javascript
alert(lang);//php
//删除
var removed = lang.splice(1,1);
alert(lang); //php,javascript
alert(removed); //java ,返回删除的项
//插入
var insert = lang.splice(0,0,"asp"); //从第0个位置开始插入
alert(insert); //返回[]
alert(lang); //["asp", "php", "java", "javascript"]
//替换
var replace = lang.splice(1,1,"c#","ruby"); //删除一项,插入两项
alert(lang); //asp,c#,ruby ,javascript
alert(replace); //php,返回删除的项 </span>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
不改变原数组的:
1.concat:连接多个数组,返回新的数组

var arr = [1,2,3];
alert(arr.concat([4,5,6]));//[1,2,3,4,5,6]
1
2
2.join:以参数作为分隔符,将所有数组成员组成一个字符串返回。如果不提供参数,默认用逗号分隔。

var arr = [1, 2, 3, 4];
arr.join(' ') // "1 2 3 4"
arr.join(' | ') // "1 | 2 | 3 | 4"
arr.join() // "1,2,3,4"
1
2
3
4
3.slice:用于截取原数组的一部分,返回一个新数组(即可用于数组也可用于字符串)。slice(start,end),第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。

var arr = ['a', 'b', 'c'];
arr.slice(0) // ["a", "b", "c"]
arr.slice(1) // ["b", "c"]
arr.slice(1, 2) // ["b"]
arr.slice(2, 6) // ["c"]
arr.slice() // ["a", "b", "c"] 无参数返回原数组

arr.slice(-2)// ["b", "c"]参数是负数,则表示倒数计算的位置
arr.slice(-2, -1) // ["b"]

//删除第index个元素
t = t.slice(0, index) + t.slice(index + 1);
1
2
3
4
5
6
7
8
9
10
11
12
4.map,filter,every,some等返回一个新数组,原数组没有变化
map():对数组的所有成员依次调用一个函数,根据函数结果返回一个新数组。

var numbers = [1, 2, 3];
numbers.map(function (n) {
return n + 1;
});
// [2, 3, 4]
numbers
// [1, 2, 3]
1
2
3
4
5
6
7
filter():参数是一个函数,所有数组成员依次执行该函数,返回结果为true的成员组成一个新数组返回。
注意:filter()不会对空数组进行检测、不会改变原始数组

let nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let res = nums.filter((num) => {
return num > 5;
});

console.log(res); // [6, 7, 8, 9, 10]
console.log(nums); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
1
2
3
4
5
6
7
8
every()与some()方法都是JS中数组的迭代方法。
共同点:
1.遍历数组;
2. 三个参数分别是item,index,arr(数组具体项,位置,数字本身);
3.返回的都是布尔值;
区别:
1.every()方法,遍历数组每一项,若全部为true,则返回true;

2.some()方法,遍历数组的每一项,若其中一项为 true,则返回true;

另外数组还有valueOf,indexOf,toString等方法
valueOf():返回数组的本身

var arr = [1, 2, 3];
arr.valueOf() // [1, 2, 3]
1
2
indexOf():返回指定元素在数组中出现的位置,如果没有出现则返回-1。

var arr = ['a', 'b', 'c'];
arr.indexOf('b') // 1
arr.indexOf('y') // -1
1
2
3
toString():返回数组的字符串形式

var arr = [1, 2, 3];
arr.toString() // "1,2,3"
var arr = [1, 2, 3, [4, 5, 6]];
arr.toString() // "1,2,3,4,5,6"
1
2
3
4
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。


注意: reduce() 对于空数组是不会执行回调函数的。

let arr=[0,1,2,3]
arr.reduce((a,b,index)=>{
debugger
return a+b; // 16
},10)
1
2
3
4
5

reduce的高级技巧 https://www.cnblogs.com/cckui/p/9267542.html

2.字符串对象
1.字符串对象的创建

var str="Hello world";
//或者
var str=new String("Hello world")
1
2
3
2.charAt():返回指定位置的字符串,比如我们想返回str字符串中,第二个字符,则可以写成charAt(1),因为字符串的下标也是从0开始,因此我们返回了第二个字符e;

var str="Hello world"; alert(str.charAt(1))
//输出e
1
2
3.indexOf(注意O要大写):可返回某个指定的字符串值在字符串中首次出现的位置。

var str="Hello world";alert(str.indexOf('e'))
//输出1
1
2
indexOf()方法还可以有第二个参数规定字符串开始检索的位置
4.split():可以按规则分割字符串

var x="86-029-19201920";alert(x.split(-))
//输出 86 029 19201920
1
2
split()方法还可以有第二个参数,表示分割的次数,如果省略,默认分割次数不限
5.substring():提取字符串,该方法有两个参数,第一个参数表示起始位置,第二个参数表示终止位置,如果省略第二个参数,默认提取到字符串的结尾。

var x="Hello world";alert(x.substring(0,4));
//输出Hello
1
2
6.substr():也可用于提取字符串,不同的是该方法的两个参数,第一个参数表示起始位置,第二个参数表示提出字符串的个数。

var x="Hello world";alert(x.substr(0,5));
//同样输出Hello
1
2
7.replace() :用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串,返回一个新的字符串。

//给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
var isPalindrome = function(s) {
// \w 匹配所有字母和数字以及下划线; \W与之相反;
//[\W_] 表示匹配下划线或者所有非字母非数字中的任意一个;/g全局匹配
let reg=/[\W_]/g;
let newStr=s.replace(reg,'').toLowerCase();
//将一个字符串转化成多个字符串,转化成数组;反转;用join连接字符串
let reverseStr=newStr.split('').reverse().join('');
return reverseStr===newStr;
};
1
2
3
4
5
6
7
8
9
10
8.trim():删除字符串前后的空格字符

let str=' Hello World! ';
alert(str.trim());//Hello World!
1
2
trim 方法实现

function myTrim(x) {
return x.replace(/^\s+|\s+$/gm,'');
}
var str = myTrim(" Hello World! ");
alert(str);//Hello World!
//不使用函数,则一行代码实现
let str=' Hello World! ';
alert(str.replace(/(^\s+)|(\s+$)/g, ""));
1
2
3
4
5
6
7
8
\s就是[\t\v\n\r\f]。表示空白符:包括空格、水平制表符、垂直制表符、换行符、回车符、换页符;
+等价于{1,},表示出现至少一次;
(p1|p2|p3)其中p1、p2和p3是子模式,用|(管道符)分隔,表示其中任何一个;
g表明可以进行全局匹配,m表明可以进行多行匹配,综合到一起就是可以进行全局多行匹配。
如下是g和m的比较:

var regx=/^b./g;
var str="bd76\ndfsdf\nsdfsdfs\ndffs\nb76dsf\nsdfsdf";
var rs=str.match(regx);
alert(rs)
// 此时加入g和不加入g,都只返回第一个匹配{bd};
//若regx=/^b./gm,则返回所有的匹配{bd,b7},注意如果regx=/^b./m,则也只返回第一个匹配,不会返回全部匹配。
//所以,加入m表明可以进行多行匹配,加入g表明可以进行全局匹配,综合到一起就是可以进行多行全局匹配
1
2
3
4
5
6
7
标志字符
g : 全局搜索 记忆方式global
i :不区分大小写 记忆方式 ignore
m :多行搜索

3.数组对象和字符串对象方法的互用
call和apply函数就能实现字符串方法和数组对象方法的互用

var x="Hello World";
var y=Array.prototype.slice.call(x);
1
2
通过call方法,将x字符串对象转为了y数组对象!!!同理也可以将数组对象转化为字符串对象

Array.from():用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

let arr = [1,1,"six","six",null,null,undefined,undefined,false,false,true,true,"",""];
// new Set 是实现数组去重,Array.from()把去重之后转换成数组
let arr2 = Array.from(new Set(arr));
console.log(arr2);//[1, "six", null, undefined, false, true, ""]
1
2
3
4
JS中的数组,对象,字符串常用的方法

数组的常用方法:
var arr =[1,2,3,4,5];
arr[0] arr[arr.length-1]//通过下标找到数组中指定的元素,访问数组的元素
arr.join(“-“) //数组转成字符串
arr.toString() //数组转成字符串
arr.push(6); //向后添加,返回新数组个数 ,原数组是添加后的数组
arr.pop(); //从后删除,返回删除的元素
arr.unshift(); //向前添加,返回个数
arr.shift(); //从前删除,返回删除的元素
arr.reverse();//反转数组
arr.sort();//排序
arr.slice();拷贝,生成新的数组
arr.splice()//截取
arr.concat();//拼接,合并
arr.indexOf();//寻找数组中的元素的索引,没有返回-1;
arr.lastIndexOf();//从数组最后找
arr.length=0;//清空数组
arr.splice(0,arr.length)//清空数组
arr=[];//清空数组
typeof(arr) //判断是否是数组
Math.max.apply(null,arr)或 Math.max(…arr)//找到数组中的最大值
Math.min.apply(null,arr)或 Math.min(…arr) //找到数组中的最小值
数组与其他值的运算(使用”+”会自动转为string,”-“会自动转为number)
arr2=[…arr1] // 数组赋值(对象扩展运算符的写法)
[…arr1, …arr2, …arr3] //合并数组
// ES5
var arr1 = str.split(”); // [ “h”, “e”, “l”, “l”, “o” ] ////字符串转化成数组
// ES6
var arr2 = […str]; // [ “h”, “e”, “l”, “l”, “o” ] //字符串转化成数组
数组去重:
方法一:
let arr1=[1,2,1,2,6,3,5,69,66,7,2,1,4,3,6,8,9663,8]
let set = new Set(arr1);
console.log(set) // {1,2,6,3,5,69,66,7,4,8,9663,8]
方法二:
Array.from();Array.of() //转换成数组并去重
数组迭代:
filter:
var arr=[1,3,6,8,45,34,90,122,9,0];
var array = arr.filter(function(element){
return element>10
})
console.log(array)
//筛选数组中大于10的值, [45, 34, 90, 122]
//查看原数组,并没有改变
console.log(arr) // [1,3,6,8,45,34,90,122,9,0]

字符串的常用方法:
var str = “hello world”;
str[0];//通过下标找到字符串指定位置的字符
str.toUpperCase() //转大写
str.toLowerCase() //转小写
str.indexOf() //寻找字符串中的元素,是否存在某个字符串,没有返回-1;
str.lastIndexOf() // 返回指定值在调用该方法的字符串中最后出现的位置,如果没找到则返回-1
str.concat() // 拼接,合并
str.slice(beginSlice,endSlice) // 返回被操作字符的子字符串,第一个参数为开始位置,第二个参数为结束位置,前包后不包(不改变原字符串)
str.substring() // 截取起始位置到终止位置到字符串
str.substr() //返回指定位置开始的指定长度的字符串
str.split() //分隔符将一个字符串分割成多个字符串,转化成数组
str.trim() //删除字符串前后的空格字符
str.repeat(count) // 构造并返回一个新字符串,该字符串是循环完成后的新字符串(不能为-1)

'abc'.repeat(0) // “”
'abc'.repeat(1) // “abc”
'abc'.repeat(2) // “abcabc”
1
2
3
str.replace() //用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串,返回一个新的字符串。
str.startsWith(“str”) //检测字符串是不是以“str”开头的,根据判断返回true,false
str.endsWith(“str”) //是不是以“str”结尾的
str.includes(“aaa”) //检测一个字符串是否在另一个字符串里包含,区分大小写
str.charAt()//根据下标查询访问字符串的某个字符,还可以使用 [ ] 的形式来访问,中括号填写的是字符串的下标
拼接字符串:
第一种方法 用连接符“+”把要连接的字符串连起来:

str="a";
str+="b";
1
2
毫无疑问,这种方法是最便捷快速的,如果只连接100个以下的字符串建议用这种方法最方便。
第二种方法 以数组作为中介用 join 连接字符串:

var arr=new Array();
arr.push(a);
arr.push(b);
var str=arr.join("");
1
2
3
4
w3school 网站介绍说这种方法要比第一种消耗更少的资源,速度也更快,后面我们通过实验再验证是否是这样。

数组和字符串的公共方法
indexOf(),lastIndexOf() ,concat() ,slice(beginSlice,endSlice)

indexOf()在数组和字符串中使用的区别
相同点
1、传参相同

var arr = [0,1,'2'];
var str="Hello world!";
console.log("Array",arr.indexOf(1,0)); //1
console.log("string",str.indexOf('d',0)); //10
1
2
3
4
2、返回值类型相同

var arr = [0,1,'2'];
var str="Hello world!";
console.log("Array",arr.indexOf(1)); //1
console.log("string",str.indexOf('s')); //-1
1
2
3
4
不同点
字符串的indexOf在传入参数不是字符串的情况下默认会转换为字符串

var str="Hello 666!";
console.log("string",str.indexOf('6')); //6
console.log("string",str.indexOf(6)); //6

//而数组的indexOf不会进行数据类的转换
var arr = [0,1,'2'];
console.log("Array",arr.indexOf(2)); //-1
console.log("Array",arr.indexOf('2')); //2

1
2
3
4
5
6
7
8
9
5.对象的常用方法:
(1)如何区分深拷贝与浅拷贝
(https://www.cnblogs.com/echolun/p/7889848.html)
简单点来说,就是假设B复制了A,当修改A时,如果B也跟着变了,说明这是浅拷贝,如果B没变,那就是深拷贝。
浅拷贝

let a=[0,1,2,3,4],
b=a;
console.log(a===b); //true
a[0]=1;
console.log(a,b); //[1, 1, 2, 3, 4] [1, 1, 2, 3, 4]
1
2
3
4
5
深拷贝

let a=1;
b=a;
console.log(a===b); //true
a=2;
console.log(a,b); //2 1
1
2
3
4
5
原因:引用数据类型(数组)–名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,所以拷贝时拷贝的是地址,而基本类型–名值存储在栈内存中。
Object.assign() // 浅拷贝,用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,它将返回目标对象
语法:

Object.assign(target, ...sources)
1
target:目标对象;
sources:源对象;
返回值:目标对象

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
1
2
3
4
5
6
7
8
9
10
如果目标对象中的属性(value)具有相同的键(key),则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。

Object.assign 浅拷贝还是深拷贝?
Object.assign 可以把 n 个源对象拷贝到目标对象中去,如下

let m ={name: {asd: '123'}}
let n = Object.assign({}, m)
console.log(n)
1
2
3
运行结果:

{name: {asd: '123'}}
1
那到底是深拷贝还是浅拷贝呢,答案是第一级属性深拷贝,以后级别属性浅拷贝 。大家看下面两段代码
例1

let s ={name: {asd: '123'}}
let d = Object.assign({}, s)
s.name.asd = '123456789' // 或者d.name.asd = '123456789'结果一样
console.log(d, s)
1
2
3
4
运行结果:

{name:{asd: "123456789"}}
{name:{asd: "123456789"}}
1
2
例2

let o ={name: {asd: '123'}}
let p = Object.assign({}, o)
o.name = '123456789'
console.log(p, o)
1
2
3
4
运行结果:

name: {asd: "123"}
{name: "123456789"}
1
2
针对深拷贝,需要使用其他办法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。
var obj= JSON.parse(JSON.stringify(obj1)) //深拷贝

var obj1 = { a: 0 , b: { c: 0}};
var obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(obj3); //{ a: 0 , b: { c: 0}};
1
2
3
4
5
Object.entries() //返回一个数组,其元素是与直接在object上找到的可枚举属性键值对相对应的数组。属性的顺序与通过手动循环对象的属性值所给出的顺序相同

var obj1 = {a:1,b:2};
var obj2 = Object.entries(obj1);
console.log(obj2) ; // [ ["a":1],["b":2] ]
1
2
3
Object.is() //判断两个值是否是相等的值,返回true或false(不能够比较数组,无效)
Object.keys() //返回一个数组,一个由一个给定对象的自身可枚举属性组成的数组
obj.hasOwnProperty(key)//检测对象有没有指定的key ,返回true或false
Object.values() //方法返回一个给定对象自己的所有可枚举属性值的数组,值的顺序与使用for…in循环相同,返回的对象的value值,与Object.key()相反

(2)apply()与call()的区别
JavaScript中的每一个Function对象都有一个apply()方法和一个call()方法
它们各自的定义:
apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法。

call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法。
相同点:
(1)可以用来代替另一个对象调用一个方法
(2)将一个函数的对象上下文从初始的上下文改变为由A指定的新对象
(3)如果没有提供A参数,那么 Global 对象被用作this对象
不同点:
apply:最多只能有两个参数——新this对象和一个数组argArray。如果给该方法传递多个参数,则把参数都写进这个数组里面,当然,即使只有一个参数,也要写进数组里。如果argArray不是一个有效的数组或arguments对象,那么将导致一个TypeError。
call:它可以接受多个参数,第一个参数与apply一样,后面则是一串参数列表。这个方法主要用在js对象各方法相互调用的时候,使当前this实例指针保持一致,或者在特殊情况下需要改变this指针。
实际上,apply和call的功能是一样的,只是传入的参数列表形式不同。
(1)基本用法

function add(a,b){
return a+b;
}
function sub(a,b){
return a-b;
}
/*apply的用法*/
var a1 = add.apply(sub,[4,2]);  //sub调用add的方法
var a2 = sub.apply(add,[4,2]);
alert(a1); //6
alert(a2); //2

/*call的用法*/
var a1 = add.call(sub,4,2);
alert(a1); //6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(2)实现继承

function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}

function Cat(name){
Animal.apply(this,[name]);
//Animal.call(this,name); // call的用法
}

var cat = new Cat("咕咕");
cat.showName(); // 咕咕
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(3)多重继承(加减)

function Class10(){
this.showSub = function(a,b){
console.log(a - b);
}
}

function Class11(){
this.showAdd = function(a,b){
console.log(a + b);
}
}

function Class12(){
Class10.apply(this);
Class11.apply(this);
// Class10.call(this);
// Class11.call(this);
}

var c2 = new Class12();
c2.showSub(3,1); // 2
c2.showAdd(3,1); // 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(4)apply的一些其他巧妙用法

Math.max 可以实现得到数组中最大的一项:
因为Math.max不支持Math.max([param1,param2])也就是数组,但是它支持Math.max(param1,param2…),所以可以根据apply的特点来解决 ,可以轻易得到一个数组中的最大项(apply会将一个数组转换为一个参数接一个参数的方式传递给方法)
var max=Math.max.apply(null,array) // 得到数组中最大的一项
1
这块在调用的时候第一个参数给了null,这是因为没有对象去调用这个方法,我只需要用这个方法帮我运算,得到返回的结果就行,所以直接传递了一个null过去。
用这种方法也可以实现得到数组中的最小项:

Math.min.apply(null,array) // 得到数组中最小的一项
1
Array.prototype.push可以实现两个数组的合并
同样push方法没有提供push一个数组,但是它提供了push(param1,param2…paramN),同样也可以用apply来转换一下这个数组,即:
var arr1=new Array("1","2","3");
var arr2=new Array("4","5","6");
Array.prototype.push.apply(arr1,arr2); //得到合并后数组的长度,因为push就是返回一个数组的长度
1
2
3

原文链接:https://blog.csdn.net/cristina_song/article/details/86597643

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!