彻底搞懂JS实例方法与包装对象
5、实例方法
Date
的实例对象,有几十个自己的方法,除了valueOf
和toString
,可以分为以下三类。
to
类:从Date
对象返回一个字符串,表示指定的时间。get
类:获取Date
对象的日期和时间。set
类:设置Date
对象的日期和时间。
5.1 Date.prototype.valueOf() 返回时间戳,等同于getTime()。(减法运算默认调用)
valueOf
方法返回实例对象距离时间零点(1970年1月1日00:00:00 UTC)对应的毫秒数,该方法等同于getTime
方法。
var d = new Date();
d.valueOf() // 1362790014817
d.getTime() // 1362790014817
预期为数值的场合,Date
实例会自动调用该方法,所以可以用下面的方法计算时间的间隔。
var start = new Date();
// ...
var end = new Date();
var elapsed = end - start; // 自动调用valueOf()方法,返回时间戳的减法运算
5.2 to 类方法(返回字符串相关)
(1)Date.prototype.toString() 返回一个完整的日期字符串(直接读取实例默认调用此方法)
toString
方法返回一个完整的日期字符串。
var d = new Date(2013, 0, 1);
d.toString()
// "Tue Jan 01 2013 00:00:00 GMT+0800 (CST)"
// "Tue Jan 01 2013 00:00:00 GMT+0800 (CST)"
因为toString
是默认的调用方法,所以如果直接读取Date
实例,就相当于调用这个方法。
(2)Date.prototype.toUTCString() 返回对应的UTC时间(世界标准时),比北京时间晚8小时
toUTCString
方法返回对应的 UTC 时间,也就是比北京时间晚8个小时。
var d = new Date(2013, 0, 1);
d.toUTCString()
// "Mon, 31 Dec 2012 16:00:00 GMT"
(3)Date.prototype.toISOString() 返回对应时间的 ISO8601 写法(UTC时间)
toISOString
方法返回对应时间的 ISO8601 写法。
var d = new Date(2013, 0, 1);
d.toISOString()
// "2012-12-31T16:00:00.000Z"
注意,toISOString
方法返回的总是 UTC 时区的时间。
(4)Date.prototype.toJSON() 返回符合JSON格式字符串,与toISOString
方法的返回结果完全相同。
toJSON
方法返回一个符合 JSON 格式的 ISO 日期字符串,与toISOString
方法的返回结果完全相同。
var d = new Date(2013, 0, 1);
d.toJSON()
// "2012-12-31T16:00:00.000Z"
(5)Date.prototype.toDateString() 返回日期字符串(不含时分秒)
toDateString
方法返回日期字符串(不含小时、分和秒)。
var d = new Date(2013, 0, 1);
d.toDateString() // "Tue Jan 01 2013"
(6)Date.prototype.toTimeString() 返回时间字符串(不含年月日)
toTimeString
方法返回时间字符串(不含年月日)。
var d = new Date(2013, 0, 1);
d.toTimeString() // "00:00:00 GMT+0800 (CST)"
(7)本地时间
以下三种方法,可以将 Date 实例转为表示本地时间的字符串。
Date.prototype.toLocaleString()
:完整的本地时间。Date.prototype.toLocaleDateString()
:本地日期(不含小时、分和秒)。Date.prototype.toLocaleTimeString()
:本地时间(不含年月日)。
下面是用法实例。
var d = new Date(2013, 0, 1);
d.toLocaleString()
// 中文版浏览器为"2013年1月1日 上午12:00:00"
// 英文版浏览器为"1/1/2013 12:00:00 AM"
d.toLocaleDateString()
// 中文版浏览器为"2013年1月1日"
// 英文版浏览器为"1/1/2013"
d.toLocaleTimeString()
// 中文版浏览器为"上午12:00:00"
// 英文版浏览器为"12:00:00 AM"
这三个方法都有两个可选的参数。
dateObj.toLocaleString([locales[, options]])
dateObj.toLocaleDateString([locales[, options]])
dateObj.toLocaleTimeString([locales[, options]])
这两个参数中,locales
是一个指定所用语言的字符串,options
是一个配置对象。下面是locales
的例子。
var d = new Date(2013, 0, 1);
d.toLocaleString('en-US') // "1/1/2013, 12:00:00 AM"
d.toLocaleString('zh-CN') // "2013/1/1 上午12:00:00"
d.toLocaleDateString('en-US') // "1/1/2013"
d.toLocaleDateString('zh-CN') // "2013/1/1"
d.toLocaleTimeString('en-US') // "12:00:00 AM"
d.toLocaleTimeString('zh-CN') // "上午12:00:00"
下面是options
的例子。
var d = new Date(2013, 0, 1);
// 时间格式
// 下面的设置是,星期和月份为完整文字,年份和日期为数字
d.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
})
// "Tuesday, January 1, 2013"
// 指定时区
d.toLocaleTimeString('en-US', {
timeZone: 'UTC',
timeZoneName: 'short'
})
// "4:00:00 PM UTC"
d.toLocaleTimeString('en-US', {
timeZone: 'Asia/Shanghai',
timeZoneName: 'long'
})
// "12:00:00 AM China Standard Time"
// 小时周期为12还是24
d.toLocaleTimeString('en-US', {
hour12: false
})
// "00:00:00"
d.toLocaleTimeString('en-US', {
hour12: true
})
// "12:00:00 AM"
5.3 get类 (获取年、月、日、时、分、秒等)
Date
对象提供了一系列get*
方法,用来获取实例对象某个方面的值。
getTime()
:返回实例距离1970年1月1日00:00:00的毫秒数,等同于valueOf
方法。(时间戳)getDate()
:返回实例对象对应每个月的几号(从1开始)。(日)getDay()
:返回星期几,星期日为0,星期一为1,以此类推。(星期)getFullYear()
:返回四位的年份。(年)getMonth()
:返回月份(0表示1月,11表示12月)。(月)getHours()
:返回小时(0-23)。(时)getMilliseconds()
:返回毫秒(0-999)。(毫秒)getMinutes()
:返回分钟(0-59)。(分)getSeconds()
:返回秒(0-59)。(秒)getTimezoneOffset()
:返回当前时间与 UTC 的时区差异,以分钟表示,返回结果考虑到了夏令时因素。(与UTC差异)
所有这些get*
方法返回的都是整数,不同方法返回值的范围不一样。
- 分钟和秒:0 到 59
- 小时:0 到 23
- 星期:0(星期天)到 6(星期六)
- 日期:1 到 31
- 月份:0(一月)到 11(十二月)
var d = new Date('January 6, 2013');
d.getDate() // 6
d.getMonth() // 0
d.getFullYear() // 2013
d.getTimezoneOffset() // -480 UTC时间减去当前时间,单位是分钟
上面代码中,最后一行返回-480
,即 UTC 时间减去当前时间,单位是分钟。-480
表示 UTC 比当前时间少480分钟,即当前时区比 UTC 早8个小时。
例子:计算本年度还剩下多少天
function leftDays() {
var today = new Date();
var endYear = new Date(today.getFullYear(), 11, 31, 23, 59, 59, 999);
var msPerDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
return Math.round((endYear.getTime() - today.getTime()) / msPerDay);
}
上面这些get*
方法返回的都是当前时区的时间,Date
对象还提供了这些方法对应的 UTC 版本,用来返回 UTC 时间。
获取UTC时区相关方法:
getUTCDate()
getUTCFullYear()
getUTCMonth()
getUTCDay()
getUTCHours()
getUTCMinutes()
getUTCSeconds()
getUTCMilliseconds()
var d = new Date('January 6, 2013');
d.getDate() // 6
d.getUTCDate() // 5
上面代码中,实例对象d
表示当前时区(东八时区)的1月6日0点0分0秒,这个时间对于当前时区来说是1月6日,所以getDate
方法返回6,对于 UTC 时区来说是1月5日,所以getUTCDate
方法返回5。
5.4 set 类方法
Date
对象提供了一系列set*
方法,用来设置实例对象的各个方面。
setDate(date)
:设置实例对象对应的每个月的几号(1-31),返回改变后毫秒时间戳。setFullYear(year [, month, date])
:设置四位年份。setHours(hour [, min, sec, ms])
:设置小时(0-23)。setMilliseconds()
:设置毫秒(0-999)。setMinutes(min [, sec, ms])
:设置分钟(0-59)。setMonth(month [, date])
:设置月份(0-11)。setSeconds(sec [, ms])
:设置秒(0-59)。setTime(milliseconds)
:设置毫秒时间戳。
这些方法基本是跟get*
方法一一对应的,但是没有setDay
方法,因为星期几是计算出来的,而不是设置的。另外,需要注意的是,凡是涉及到设置月份,都是从0开始算的,即0
是1月,11
是12月。
var d = new Date ('January 6, 2013');
d // Sun Jan 06 2013 00:00:00 GMT+0800 (CST)
d.setDate(9) // 1357660800000
d // Wed Jan 09 2013 00:00:00 GMT+0800 (CST)
set*
方法的参数都会自动折算。以setDate
为例,如果参数超过当月的最大天数,则向下一个月顺延,如果参数是负数,表示从上个月的最后一天开始减去的天数。
var d1 = new Date('January 6, 2013');
d1.setDate(32) // 1359648000000
d1 // Fri Feb 01 2013 00:00:00 GMT+0800 (CST)
var d2 = new Date ('January 6, 2013');
d.setDate(-1) // 1356796800000
d // Sun Dec 30 2012 00:00:00 GMT+0800 (CST)
**set
类方法和get
类方法,可以结合使用,得到相对时间。**
var d = new Date();
// 将日期向后推1000天
d.setDate(d.getDate() + 1000);
// 将时间设为6小时后
d.setHours(d.getHours() + 6);
// 将年份设为去年
d.setFullYear(d.getFullYear() - 1);
set*
系列方法除了setTime()
,都有对应的 UTC 版本,即设置 UTC 时区的时间。
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
var d = new Date('January 6, 2013');
d.getUTCHours() // 16
d.setUTCHours(22) // 1357423200000
d // Sun Jan 06 2013 06:00:00 GMT+0800 (CST)
上面代码中,本地时区(东八时区)的1月6日0点0分,是 UTC 时区的前一天下午16点。设为 UTC 时区的22点以后,就变为本地时区的上午6点。
Object.prototype.toLocaleString()
Object.prototype.toLocaleString
方法与toString
的返回结果一模一样的,也是返回一个值的字符串形式。
var obj = {};
obj.toString(obj) // "[object Object]"
obj.toLocaleString(obj) // "[object Object]"
这个方法的主要作用是留出一个接口,让各种不同的对象实现自己版本的toLocaleString
,用来返回针对某些地域的特定的值。
var person = {
toString: function () {
return 'Henry Norman Bethune';
},
toLocaleString: function () {
return '白求恩';
}
};
person.toString() // Henry Norman Bethune
person.toLocaleString() // 白求恩
上面代码中,toString()
方法返回对象的一般字符串形式,toLocaleString()
方法它返回本地的字符串形式。
目前,主要有三个对象自定义了toLocaleString
方法。
- Array.prototype.toLocaleString()
- Number.prototype.toLocaleString()
- Date.prototype.toLocaleString()
比如来说,日期的实例对象的toString
和toLocaleString
返回值就不一样,而且toLocaleString
的返回值跟用户设定的所在地域相关。
var date = new Date();
date.toString() // "Sun Oct 06 2019 15:50:04 GMT+0800 (中国标准时间)"
date.toLocaleString() // "2019/10/6 下午3:50:04"
filter() 过滤
filter
方法用于过滤数组成员,满足条件的成员组成一个新数组返回。
它的参数是一个函数,所有数组成员依次执行该函数,返回结果为true
的成员组成一个新数组返回。
该方法不会改变原数组。
[1,2,3,4,5].filter(function(elem){
return elem > 3
})
// [4,5]
上面代码将大于3
的数组成员,作为一个新数组返回。
var arr = [0, 1, 'a', false];
arr.filter(Boolean)
// [1, "a"]
上面代码中,filter
方法返回数组arr
里面所有布尔值为true
的成员。
filter
方法的参数函数可以接受三个参数**:当前成员,当前位置、整个数组。**
[1, 2, 3, 4, 5].filter(function (elem, index, arr) { // 当前成员,当前位置、整个数组
return index % 2 === 0;
});
// [1, 3, 5]
上面代码返回偶数位置的成员组成的新数组。
filter
方法还可以接受第二个参数,用来绑定参数函数内部的this
变量。
var obj = { MAX: 3 };
var myFilter = function (item) {
if (item > this.MAX) return true; // this指向obj
};
var arr = [2, 8, 3, 4, 1, 3, 2, 9];
arr.filter(myFilter, obj) // [8, 4, 9] // 使myFilter内部this指向obj
上面代码中,过滤器myFilter
内部有this
变量,它可以被filter
方法的第二个参数obj
绑定,返回大于3
的成员。
some()某个,every()每个
这两个方法类似“断言”(assert),返回一个布尔值,表示判断数组成员是否符合某种条件。
它们接受一个函数作为参数,所有数组成员依次执行该函数。该函数接受三个参数:当前成员、当前位置、整个数组,然后返回一个布尔值。
some
方法是只要一个成员的返回值是true
,则整个some
方法的返回值就是true
,否则返回false
。
var arr = [1,2,3,4,5]
arr.some(function(elem,index,arr){ // 返回值中有一个为true则此方法返回true
return elem >= 3
})
// true
上面代码中,如果数组arr
有一个成员大于等于3,some
方法就返回true
。
every
方法是所有成员的返回值都是true
,整个every
方法才返回true
,否则返回false
。
var arr = [1, 2, 3, 4, 5];
arr.every(function (elem, index, arr) { // 每个返回值都为true,此方法才返回true,否则返回false
return elem >= 3;
});
// false
上面代码中,数组arr
并非所有成员大于等于3
,所以返回false
。
注意,对于空数组,some
方法返回false
,every
方法返回true
,回调函数都不会执行。
function isEven(x) { return x % 2 === 0 } // 不会执行此函数
[].some(isEven) // false
[].every(isEven) // true
some
和every
方法还可以接受第二个参数,用来绑定参数函数内部的this
变量。
var arr = [1,2,3]
var obj = {MAX:0}
function fn(elem) {
return elem > this.MAX // this指向obj
}
arr.some(fn,obj) // true
arr.every(fn,obj) // true
reduce() 累计器,reduceRight() 反向累计器
reduce
方法和reduceRight
方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce
是从左到右处理(从第一个成员到最后一个成员),reduceRight
则是从右到左(从最后一个成员到第一个成员),其他完全一样。
[1,2,3,4,5].reduce(function(a,b,c,d){
// 记住a是默认是第一个成员,然后是上一次运算的返回值。
console.log(a,b)
console.log(c)
return a+b
})
// 1 2
// 3 3
// 6 4
// 10 5
// 最终结果 15
上面代码中,reduce
方法求出数组所有成员的和。第一次执行,a
是数组的第一个成员1
,b
是数组的第二个成员2
。第二次执行,a
为上一轮的返回值3
,b
为第三个成员3
。第三次执行,a
为上一轮的返回值6
,b
为第四个成员4
。第四次执行,a
为上一轮返回值10
,b
为第五个成员5
。至此所有成员遍历完成,整个方法的返回值就是最后一轮的返回值15
。
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
// 说明:中括号代表可选参数
reduce
方法和reduceRight
方法的第一个参数都是一个callback
函数。该函数接受以下四个参数。
-
累积变量,默认为数组的第一个成员
-
当前变量,默认为数组的第二个成员
-
当前位置(默认从1开始), 如果提供了
initialValue
,则起始索引号为0,否则为1。 (可选) -
原数组(可选)
`initialValue`可选
作为第一次调用 callback函数时
的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
如果要对累积变量指定初值,可以把它放在reduce
方法和reduceRight
方法的第二个参数。
[1, 2, 3, 4, 5].reduce(function (a, b) {
return a + b;
}, 10);
// 25
上面代码指定参数a
的初值为10,所以数组从10开始累加,最终结果为25。注意,这时b
是从数组的第一个成员开始遍历。
上面的第二个参数相当于设定了默认值,处理空数组时尤其有用。
function add(prev, cur) {
return prev + cur;
}
[].reduce(add) // 报错
// TypeError: Reduce of empty array with no initial value
[].reduce(add, 1)
// 1
上面代码中,由于空数组取不到初始值,reduce
方法会报错。这时,加上第二个参数,就能保证总是会返回一个值。
下面是一个reduceRight
方法的例子。
function subtract(prev, cur) {
return prev - cur;
}
[3, 2, 1].reduce(subtract) // 0
[3, 2, 1].reduceRight(subtract) // -4
上面代码中,reduce
方法相当于3
减去2
再减去1
,reduceRight
方法相当于1
减去2
再减去3
。
应用-找出字符最长的数组成员
由于这两个方法会遍历数组,所以实际上还可以用来做一些遍历相关的操作。比如,找出字符长度最长的数组成员。
function findLongest(entries) {
return entries.reduce(function (longest, entry) {
return entry.length > longest.length ? entry : longest;
}, '');
}
findLongest(['aaa', 'bb', 'c']) // "aaa"
上面代码中,reduce
的参数函数会将字符长度较长的那个数组成员,作为累积值。这导致遍历所有成员之后,累积值就是字符长度最长的那个成员。
应用-按属性对object分类
var people = [
{ name: 'Alice', age: 21 },
{ name: 'Max', age: 20 },
{ name: 'Jane', age: 20 }
];
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
var key = obj[property];
if (!acc[key]) {// 当{}中没有对应分类属性时,先创建改属性
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {}); // 初始值为{}
}
var groupedPeople = groupBy(people, 'age');
// groupedPeople is:
// {
// 20: [
// { name: 'Max', age: 20 },
// { name: 'Jane', age: 20 }
// ],
// 21: [{ name: 'Alice', age: 21 }]
// }
indexOf() 搜索成员第一个出现的位置,lastIndexOf() 搜索成员最后出现的位置
indexOf
方法返回给定元素在数组中第一次出现的位置,如果没有则返回-1
。
indexOf语法
arr.indexOf(searchElement[, fromIndex = 0])
var a = [1,2,3,4,5]
a.indexOf(3) // 2 3在数组a中第一次出现的位置为2
a.indexOf(6) // -1 6在数组a中没有出现,返回-1
indexOf
方法还可以接受第二个参数,表示搜索的开始位置。
['a', 'b', 'c'].indexOf('a', 1) // -1 从1位置开始搜索a,没有搜索到
上面代码从1号位置开始搜索字符a
,结果为-1
,表示没有搜索到。
lastIndexOf()语法
arr.lastIndexOf(searchElement[, fromIndex = arr.length - 1])
lastIndexOf
方法返回给定元素在数组中最后一次出现的位置,如果没有则返回-1
。
var a = [2,3,4,2]
a.lastIndexOf(2) //3 2在数组a中最后一次出现的位置为3
a.lastIndexOf(5) //-1
注意,这两个方法不能用来搜索NaN
的位置,即它们无法确定数组成员是否包含NaN
。
[NaN].indexOf(NaN) // -1
[NaN].lastIndexOf(NaN) // -1
这是因为这两个方法内部,使用严格相等运算符(===
)进行比较,而NaN
是唯一一个不等于自身的值。
链式使用
上面这些数组方法之中,有不少返回的还是数组,所以可以链式使用。
var users = [
{name: 'tom', email: 'tom@example.com'},
{name: 'peter', email: 'peter@example.com'}
];
users
.map(function (user) {
return user.email;
}) // 对每个成员进行遍历,使用返回值组成一个新的数组并返回
.filter(function (email) { // 过滤返回值为false的成员,并返回一个过滤掉的新数组
return /^t/.test(email);
})
.forEach(function (email) { // 遍历数组
console.log(email);
});
// "tom@example.com"
上面代码中,先产生一个所有 Email 地址组成的数组,然后再过滤出以t
开头的 Email 地址,最后将它打印出来。
方法的返回值能满足下一个方法的调用,即可使用链式调用。
四、包装对象
1、定义
对象是JavaScript语言中最主要的数据类型,三种原始类型的值——数字、字符串、布尔值 在一定条件下,也会自动转为对象,也就是原始类型的包装对象(wrapper)
所谓“包装对象”,指的是与数字、字符串、布尔值分别相对应的Number
、String
、Boolean
三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象。
var v1 = new Number(123);
var v2 = new String('abc');
var v3 = new Boolean(true);
typeof v1 // "object"
typeof v2 // "object"
typeof v3 // "object"
v1 === 123 // false
v2 === 'abc' // false
v3 === true // false
上面代码中,基于原始类型的值,生成了三个对应的包装对象。可以看到,v1
、v2
、v3
都是对象,且与对应的简单类型值不相等。
包装对象的设计目的,首先是使得“对象”这种类型可以覆盖 JavaScript 所有的值,整门语言有一个通用的数据模型,其次是使得原始类型的值也有办法调用自己的方法。
Number
、String
和Boolean
这三个原生对象,如果不作为构造函数调用(即调用时不加new
),而是作为普通函数调用,常常用于将任意类型的值转为数值、字符串和布尔值。
// 字符串转为数值
Number('123') // 123
// 数值转为字符串
String(123) // "123"
// 数值转为布尔值
Boolean(123) // true
上面这种数据类型的转换,详细请见《数据类型转换》一节。
总结一下,这三个对象作为构造函数使用(带有new
)时,可以将原始类型的值转为对象;作为普通函数使用时(不带有new
),可以将任意类型的值,转为原始类型的值。
2、实例方法
三种包装对象各自提供了许多实例方法,详见后文。这里介绍两种它们共同具有、从Object
对象继承的方法:valueOf()
和toString()
。
2.1 valueOf()
valueOf()
方法返回包装对象实例对应的原始类型的值。
new Number(123).valueOf() // 123
new String('abc').valueOf() // "abc"
new Boolean(true).valueOf() // true
2.2 toString()
toString()
方法返回对应的字符串形式。
new Number(123).toString() // "123"
new String('abc').toString() // "abc"
new Boolean(true).toString() // "true"
3、原始类型与实例对象的自动转换
某些场合,原始类型的值会自动当作包装对象调用,即调用包装对象的属性和方法。这时,JavaScript 引擎会自动将原始类型的值转为包装对象实例,并在使用后立刻销毁实例。
比如,字符串可以调用length
属性,返回字符串的长度。
'abc'.length // 3
上面代码中,abc
是一个字符串,本身不是对象,不能调用length
属性。JavaScript 引擎自动将其转为包装对象,在这个对象上调用length
属性。调用结束后,这个临时对象就会被销毁。这就叫原始类型与实例对象的自动转换。
var str = 'abc';
str.length // 3
//等同于
var strObj = new String(str)
// String{
// 0:'a',1:'b',2:'c',length:3,[[PrimitiveValue]]: "abc"
// }
strObj.length // 3
上面代码中,字符串abc
的包装对象提供了多个属性,length
只是其中之一。
自动转换生成的包装对象是只读的,无法修改。所以,字符串无法添加新属性。
var s = 'Hello World';
s.x = 123;
s.x // undefined
上面代码为字符串s
添加了一个x
属性,结果无效,总是返回undefined
。
另一方面,调用结束后,包装对象实例会自动销毁。这意味着,下一次调用字符串的属性时,实际是调用一个新生成的对象,而不是上一次调用时生成的那个对象,所以取不到赋值在上一个对象的属性。如果要为字符串添加属性,只有在它的原型对象String.prototype
上定义(参见《面向对象编程》章节)。
4、自定义方法
除了原生的实例方法,包装对象还可以自定义方法和属性,供原始类型的值直接调用。
比如,我们可以新增一个double
方法,使得字符串和数字翻倍。
String.prototype.double = function () { // String是一个方法,String.prototype本质是一个实例对象
return this.valueOf() + this.valueOf();
};
'abc'.double()
// abcabc
Number.prototype.double = function () {
return this.valueOf() + this.valueOf();
};
(123).double() // 246 // 不加括号时点运算符会被解释成小数点
上面代码在String
和Number
这两个对象的原型上面,分别自定义了一个方法,从而可以在所有实例对象上调用。注意,最后一张的123
外面必须要加上圆括号,否则后面的点运算符(.
)会被解释成小数点。
- 点赞
- 收藏
- 关注作者
评论(0)