《JavaScript 闯关记》之基础包装范例

为了便于操纵基础范例值,JavaScript 还供应了3个特别的援用范例:BooleanNumberString。实际上,每当读取一个基础范例值的时刻,背景就会建立一个对应的基础包装范例的对象,从而让我们能够挪用一些要领来操纵这些数据。来看下面的例子。

var s1 = "some text";
var s2 = s1.substring(2);

这个例子中的变量 s1 包括一个字符串,字符串固然是基础范例值。而下一行挪用了 s1substring() 要领,并将返回的效果保留在了 s2 中。我们晓得,基础范例值不是对象,因而从逻辑上讲它们不该该有要领(只管如我们所愿,它们确切有要领)。实在,为了让我们完成这类直观的操纵,背景已自动完成了一系列的处置惩罚。当第二行代码接见 s1 时,接见历程处于一种读取情势,也就是要从内存中读取这个字符串的值。而在读取情势中接见字符串时,背景都邑自动完成以下处置惩罚。

  1. 建立 String 范例的一个实例;

  2. 在实例上挪用指定的要领;

  3. 烧毁这个实例。

能够将以上三个步骤设想成是实行了以下 JavaScript 代码。

var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;

经由此番处置惩罚,基础的字符串值就变得跟对象一样了。而且,上面这三个步骤也离别适用于 BooleanNumber 范例对应的布尔值和数字值。

援用范例与基础包装范例的主要辨别就是对象的生存期。运用 new 操纵符建立的援用范例的实例,在实行流脱离当前作用域之前都一向保留在内存中。而自动建立的基础包装范例的对象,则只存在于一行代码的实行霎时,然后立即被烧毁。这意味着我们不能在运转时为基础范例值增加属性和要领。来看下面的例子:

var s1 = "some text";
s1.color = "red";
console.log(s1.color);   // undefined

固然,能够显式地挪用 BooleanNumberString 来建立基础包装范例的对象。不过,应当在相对必要的状况下再如许做,因为这类做法很轻易让人分不清自身是在处置惩罚「基础范例」照样「援用范例」的值。对基础包装范例的实例挪用 typeof 会返回 "object",而且一切基础包装范例的对象都邑被转换为布尔值 true

Object 组织函数也会像工场要领一样,依据传入值的范例返回响应基础包装范例的实例。比方:

var obj = new Object("some text");
console.log(obj instanceof String);   // true

把字符串传给 Object 组织函数,就会建立 String 的实例;而传入数值参数会获得 Number 的实例,传入布尔值参数就会获得 Boolean 的实例。

要注重的是,运用 new 挪用基础包装范例的组织函数,与直接挪用同名的转型函数是不一样的。 比方:

var value = "25";
var number = Number(value);  // 转型函数
console.log(typeof number);  // "number"

var obj = new Number(value); // 组织函数
console.log(typeof obj);     // "object"

只管我们不发起显式地建立基础包装范例的对象,但它们操纵基础范例值的才能照样相称主要的。而每一个基础包装范例都供应了操纵响应值的便利要领。

 Boolean 范例

Boolean 范例是与布尔值对应的援用范例。要建立 Boolean 对象,能够像下面如许挪用 Boolean 组织函数并传入 truefalse 值。

var booleanObject = new Boolean(true);

Boolean 范例的实例重写了 valueOf() 要领,返回基础范例值 truefalse;重写了 toString() 要领,返回字符串 "true""false"。但是,Boolean 对象在 JavaScript 中的用途不大,因为它经常会形成人们的误会。个中最常见的题目就是在布尔表达式中运用 Boolean 对象,比方:

var falseObject = new Boolean(false);
var result = falseObject && true;
console.log(result);  // true

var falseValue = false;
result = falseValue && true;
console.log(result);  // false

在这个例子中,我们运用 false 值建立了一个 Boolean 对象。然后,将这个对象与基础范例值 true 构成了逻辑与表达式。在布尔运算中,false && true 即是 false。但是,示例中的这行代码是对 falseObject 而不是对它的值 false 举行求值。布尔表达式中的一切对象都邑被转换为 true,因而 falseObject 对象在布尔表达式中代表的是 true。效果,true && true 固然就即是 true 了。

基础范例与援用范例的布尔值另有两个辨别。起首,typeof 操纵符对基础范例返回 "boolean",而对援用范例返回 "object"。其次,因为 Boolean 对象是 Boolean 范例的实例,所以运用 instanceof 操纵符测试 Boolean 对象会返回 true,而测试基础范例的布尔值则返回 false。比方:

console.log(typeof falseObject);   // object
console.log(typeof falseValue);    // boolean
console.log(falseObject instanceof Boolean);  // true
console.log(falseValue instanceof Boolean);   // false

明白基础范例的布尔值与 Boolean 对象之间的辨别非常主要,我们的发起是永久不要运用 Boolean 对象。

 Number 范例

Number 是与数字值对应的援用范例。要建立 Number 对象,能够在挪用 Number 组织函数时向个中通报响应的数值。下面是一个例子。

var numberObject = new Number(10);

Boolean 范例一样,Number 范例也重写了 valueOf()toLocaleString()toString() 要领。重写后的 valueOf() 要领返回对象示意的基础范例的数值,别的两个要领则返回字符串情势的数值。能够为 toString() 要领通报一个示意基数的参数,通知它返回几进制数值的字符串情势,以下面的例子所示。

var num = 10;
console.log(num.toString());     // "10"
console.log(num.toString(2));    // "1010"
console.log(num.toString(8));    // "12"
console.log(num.toString(10));   // "10"
console.log(num.toString(16));   // "a"

除了继续的要领以外,Number 范例还供应了一些用于将数值花样化为字符串的要领。个中,toFixed() 要领会根据指定的小数位返回数值的字符串示意,比方:

var num = 10;
console.log(num.toFixed(2));    // "10.00"

这里给 toFixed() 要领传入了数值 2,意义是显现几位小数。因而,这个要领返回了 "10.00",即以 0 填补了必要的小数位。假如数值自身包括的小数位比指定的还多,那末靠近指定的最大小数位的值就会舍入,以下面的例子所示。

var num = 10.005;
console.log(num.toFixed(2));    // "10.01"

能够自动舍入的特征,使得 toFixed() 要领很合适处置惩罚货币值。

但须要注重的是,差别浏览器给这个要领设定的舍入划定规矩能够会有所差别。

在给 toFixed() 传入0的状况下,IE8 及之前版本不能正确舍入局限在{(-0.94,-0.5],[0.5,0.94)}之间的值。关于这个局限内的值,IE8 会返回0,而不是-1或1;其他浏览器都能返回正确的值。IE9 修复了这个题目。

toFixed() 要领能够示意带有0到20个小数位的数值。但这只是规范完成的局限,有些浏览器也能够支撑更多位数。

别的可用于花样化数值的要领是 toExponential(),该要领返回以指数示意法(也称 e 示意法)示意的数值的字符串情势。与 toFixed() 一样,toExponential() 也吸收一个参数,而且该参数一样也是指定输出效果中的小数位数。看下面的例子。

var num = 10;
console.log(num.toExponential(1));     // "1.0e+1"

以上代码输出了 "1.0e+1";不过,这么小的数值平常没必要运用 e 示意法。假如你想获得示意某个数值的最合适的花样,就应当运用 toPrecision() 要领。

关于一个数值来说,toPrecision() 要领能够会返回牢固大小(fixed)花样,也能够返回指数(exponential)花样;详细划定规矩是看哪一种花样最合适。这个要领吸收一个参数,即示意数值的一切数字的位数(不包括指数部份)。请看下面的例子。

var num = 99;
console.log(num.toPrecision(1));     // "1e+2"
console.log(num.toPrecision(2));     // "99"
console.log(num.toPrecision(3));     // "99.0"

以上代码起首完成的使命是以一名数来示意 99,效果是 "1e+2",即 100。因为一名数没法正确地示意 99,因而 toPrecision() 就将它向上舍入为 100,如许就能够运用一名数来示意它了。而接下来的用两位数示意 99,固然照样 "99"。末了,在想以三位数示意 99 时,toPrecision() 要领返回了 "99.0"。实际上,toPrecision() 会依据要处置惩罚的数值决议究竟是挪用 toFixed() 照样挪用 toExponential()。而这三个要领都能够经由过程向上或向下舍入,做到以最正确的情势来示意带有正确小数位的值。

toPrecision() 要领能够表现1到21位小数。但这只是规范完成的局限,有些浏览器也能够支撑更多位数。

Boolean 对象相似,Number 对象也以背景体式格局为数值供应了主要的功用。但与此同时,我们依然不发起直接实例化 Number 范例,而缘由与显式建立 Boolean 对象一样。详细来说,就是在运用 typeofinstanceof 操纵符测试基础范例数值与援用范例数值时,获得的效果完整差别,以下面的例子所示。

var numberObject = new Number(10);
var numberValue = 10;
console.log(typeof numberObject);   // "object"
console.log(typeof numberValue);    // "number"
console.log(numberObject instanceof Number);  // true
console.log(numberValue instanceof Number);   // false

String 范例

String 范例是字符串的对象包装范例,能够像下面如许运用 String 组织函数来建立。

var stringObject = new String("hello world");

String 对象的要领也能够在一切基础的字符串值中接见到。个中,继续的 valueOf()toLocaleString()toString() 要领,都返回对象所示意的基础字符串值。

String 范例的每一个实例都有一个 length 属性,示意字符串中包括多个字符。来看下面的例子。

var stringValue = "hello world";
console.log(stringValue.length);     // 11

应当注重的是,纵然字符串中包括双字节字符(不是占一个字节的 ASCII 字符),每一个字符也依然算一个字符。比方:

var stringValue = "大家好";
console.log(stringValue.length);     // 3

String 范例供应了许多要领,用于辅佐完成对 JavaScript 中字符串的剖析和操纵。

字符要领

两个用于接见字符串中特定字符的要领是:charAt()charCodeAt()。这两个要领都吸收一个参数,即基于0的字符位置。个中,charAt() 要领以单字符字符串的情势返回给定位置的谁人字符(JavaScript 中没有字符范例)。比方:

var stringValue = "hello world";
console.log(stringValue.charAt(1));  // "e"

假如你想获得的不是字符而是字符编码,那末就要像下面如许运用 charCodeAt() 了。比方:

var stringValue = "hello world";
console.log(stringValue.charCodeAt(1));  // 101,101是小写字母"e"的字符编码

ECMAScript 5 还定义了另一个接见一般字符的要领。在支撑浏览器中,能够运用方括号加数字索引来接见字符串中的特定字符,以下面的例子所示。

var stringValue = "hello world";
console.log(stringValue[1]);   // "e"

字符串操纵要领

下面引见与操纵字符串有关的几个要领。第一个就是 concat(),用于将一或多个字符串拼接起来,返回拼接获得的新字符串。先来看一个例子。

var stringValue = "hello ";
var result = stringValue.concat("world");

console.log(result);        // "hello world"
console.log(stringValue);   // "hello"

实际上,concat() 要领能够接收恣意多个参数,也就是说能够经由过程它拼接恣意多个字符串。再看一个例子:

var stringValue = "hello ";
var result = stringValue.concat("world", "!");

console.log(result);        // "hello world!"
console.log(stringValue);   // "hello"

虽然 concat() 是特地用来拼接字符串的要领,但实践中运用更多的照样加号操纵符 + 。而且,运用加号操纵符 + 在大多数状况下都比运用 concat()要领要简便易行(特别是在拼接多个字符串的状况下)。

JavaScript 还供应了三个基于子字符串建立新字符串的要领:slice()substr()substring()。这三个要领都邑返回被操纵字符串的一个子字符串,而且也都接收一或两个参数。第一个参数指定子字符串的最先位置,第二个参数(在指定的状况下)示意子字符串到哪里完毕。详细来说,slice()substring() 的第二个参数指定的是子字符串末了一个字符背面的位置。而 substr() 的第二个参数指定的则是返回的字符个数。假如没有给这些要领通报第二个参数,则将字符串的长度作为完毕位置。与 concat() 要领一样,slice()substr()substring()也不会修正字符串自身的值,它们只是返回一个基础范例的字符串值,对原始字符串没有任何影响。请看下面的例子。

var stringValue = "hello world";
console.log(stringValue.slice(3));            // "lo world"
console.log(stringValue.substring(3));        // "lo world"
console.log(stringValue.substr(3));           // "lo world"
console.log(stringValue.slice(3, 7));         // "lo w"
console.log(stringValue.substring(3,7));      // "lo w"
console.log(stringValue.substr(3, 7));        // "lo worl"

在通报给这些要领的参数是负值的状况下,它们的行动就不尽雷同了。个中,slice() 要领会将传入的负值与字符串的长度相加,substr() 要领将负的第一个参数加上字符串的长度,而将负的第二个参数转换为0。末了,substring() 要领会把一切负值参数都转换为0。下面来看例子。

var stringValue = "hello world";
console.log(stringValue.slice(-3));           // "rld"
console.log(stringValue.substring(-3));       // "hello world"
console.log(stringValue.substr(-3));          // "rld"
console.log(stringValue.slice(3, -4));        // "lo w"
console.log(stringValue.substring(3, -4));    // "hel"
console.log(stringValue.substr(3, -4));       //""(空字符串)

字符串位置要领

有两个能够从字符串中查找子字符串的要领:indexOf()lastIndexOf()。这两个要领都是从一个字符串中搜刮给定的子字符串,然后返子字符串的位置(假如没有找到该子字符串,则返回-1)。这两个要领的辨别在于:indexOf() 要领从字符串的开首向后搜刮子字符串,而 lastIndexOf() 要领是从字符串的末端向前搜刮子字符串。照样来看一个例子吧。

var stringValue = "hello world";
console.log(stringValue.indexOf("o"));             // 4
console.log(stringValue.lastIndexOf("o"));         // 7

这两个要领都能够吸收可选的第二个参数,示意从字符串中的哪一个位置最先搜刮。换句话说,indexOf()会从该参数指定的位置向后搜刮,疏忽该位置之前的一切字符;而lastIndexOf()则会从指定的位置向前搜刮,疏忽该位置以后的一切字符。看下面的例子。

var stringValue = "hello world";
console.log(stringValue.indexOf("o", 6));          // 7
console.log(stringValue.lastIndexOf("o", 6));      // 4

在运用第二个参数的状况下,能够经由过程轮回挪用 indexOf()lastIndexOf() 来找到一切婚配的子字符串,以下面的例子所示:

var stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
var positions = new Array();
var pos = stringValue.indexOf("e");

while(pos > -1){
    positions.push(pos);
    pos = stringValue.indexOf("e", pos + 1);
}
console.log(positions);    // "3,24,32,35,52"

trim() 要领

ECMAScript 5 为一切字符串定义了 trim() 要领。这个要领会建立一个字符串的副本,删除前置及后缀的一切空格,然后返回效果。比方:

var stringValue = "   hello world   ";
var trimmedStringValue = stringValue.trim();
console.log(stringValue);            // "   hello world   "
console.log(trimmedStringValue);     // "hello world" 

字符串大小写转换要领

JavaScript 中触及字符串大小写转换的要领有4个:toLowerCase()toLocaleLowerCase()toUpperCase()toLocaleUpperCase()。个中,toLowerCase()toUpperCase() 是两个典范的要领,自创自 java.lang.String 中的同名要领。而 toLocaleLowerCase()toLocaleUpperCase() 要领则是针对特定区域的完成。对有些区域来说,针对区域的要领与其通用要领获得的效果雷同,但少数言语(如土耳其语)会为 Unicode 大小写转换运用特别的划定规矩,这时刻就必须运用针对区域的要领来保证完成正确的转换。以下是几个例子。

var stringValue = "hello world";
console.log(stringValue.toLocaleUpperCase());  // "HELLO WORLD"
console.log(stringValue.toUpperCase());        // "HELLO WORLD"
console.log(stringValue.toLocaleLowerCase());  // "hello world"
console.log(stringValue.toLowerCase());        // "hello world"

平常来说,在不晓得自身的代码将在哪一种言语环境中运转的状况下,照样运用针对区域的要领更稳妥一些。

字符串的情势婚配要领

String 范例定义了几个用于在字符串中婚配情势的要领。第一个要领就是 match(),在字符串上挪用这个要领,本质上与挪用 RegExpexec() 要领雷同。match() 要领只接收一个参数,要么是一个正则表达式,要么是一个 RegExp 对象。来看下面的例子。

var text = "cat, bat, sat, fat"; 
var pattern = /.at/;

// 与pattern.exec(text)雷同
var matches = text.match(pattern);
console.log(matches.index);               // 0
console.log(matches[0]);                  // "cat"
console.log(pattern.lastIndex);           // 0

另一个用于查找情势的要领是 search()。这个要领的唯一参数与 match() 要领的参数雷同:由字符串或 RegExp 对象指定的一个正则表达式。search() 要领返回字符串中第一个婚配项的索引;假如没有找到婚配项,则返回-1。而且,search() 要领始终是从字符串开首向后查找情势。看下面的例子。

var text = "cat, bat, sat, fat"; 
var pos = text.search(/at/);
console.log(pos);   // 1,即"at"第一次涌现的位置

为了简化替代子字符串的操纵,JavaScript 供应了 replace() 要领。这个要领接收两个参数:第一个参数能够是一个 RegExp 对象或许一个字符串(这个字符串不会被转换成正则表达式),第二个参数能够是一个字符串或许一个函数。假如第一个参数是字符串,那末只会替代第一个子字符串。要想替代一切子字符串,唯一的方法就是供应一个正则表达式,而且要指定全局 g 标志,以下所示。

var text = "cat, bat, sat, fat"; 
var result = text.replace("at", "ond");
console.log(result);    // "cond, bat, sat, fat"

result = text.replace(/at/g, "ond");
console.log(result);    // "cond, bond, sond, fond"

末了一个与情势婚配有关的要领是 split(),这个要领能够基于指定的分隔符将一个字符串分割成多个子字符串,并将效果放在一个数组中。分隔符能够是字符串,也能够是一个 RegExp 对象(这个要领不会将字符串算作正则表达式)。split() 要领能够接收可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会凌驾既定大小。请看下面的例子。

var colorText = "red,blue,green,yellow";
var colors1 = colorText.split(",");          // ["red", "blue", "green", "yellow"]
var colors2 = colorText.split(",", 2);       // ["red", "blue"]

localeCompare() 要领

这个要领比较两个字符串,并返回以下值中的一个:

  • 假如字符串在字母表中应当排在字符串参数之前,则返回一个负数(大多数状况下是-1,详细的值要视完成而定);

  • 假如字符串即是字符串参数,则返回0;

  • 假如字符串在字母表中应当排在字符串参数以后,则返回一个正数(大多数状况下是1,详细的值一样要视完成而定)。

下面是几个例子。

var stringValue = "yellow";       
console.log(stringValue.localeCompare("brick"));    // 1
console.log(stringValue.localeCompare("yellow"));   // 0
console.log(stringValue.localeCompare("zoo"));      // -1

这个例子比较了字符串 "yellow" 和别的几个值:"brick""yellow""zoo"。因为 "brick" 在字母表中排在 "yellow" 之前,所以 localeCompare() 返回了1;而 "yellow" 即是 "yellow",所以 localeCompare() 返回了0;末了,"zoo" 在字母表中排在 "yellow" 背面,所以 localeCompare() 返回了-1。再强调一次,因为 localeCompare() 返回的数值取决于完成,所以最好是像下面例子所示的如许运用这个要领。

function determineOrder(value) {
    var result = stringValue.localeCompare(value);
    if (result < 0){
        console.log("The string 'yellow' comes before the string '" + value + "'.");
    } else if (result > 0) {
        console.log("The string 'yellow' comes after the string '" + value + "'.");
    } else {
        console.log("The string 'yellow' is equal to the string '" + value + "'.");
    }
}

determineOrder("brick");
determineOrder("yellow");
determineOrder("zoo");

运用这类构造,就能够确保自身的代码在任何完成中都能够正确地运转了。

localeCompare() 要领比较异乎寻常的处所,就是完成所支撑的区域(国家和言语)决议了这个要领的行动。比方,美国以英语作为 JavaScript 完成的规范言语,因而 localeCompare() 就是辨别大小写的,因而大写字母在字母表中排在小写字母前头就成为了一项决议性的比较划定规矩。不过,在其他区域生怕就不是这类状况了。

fromCharCode() 要领

别的,String 组织函数自身另有一个静态要领:fromCharCode()。这个要领的使命是吸收一或多个字符编码,然后将它们转换成一个字符串。从本质上来看,这个要领与实例要领 charCodeAt() 实行的是相反的操纵。来看一个例子:

console.log(String.fromCharCode(104, 101, 108, 108, 111)); // "hello"

var s = 'hello';
for(let i=0;i<s.length;i++){
  console.log(`${s[i]}----${s[i].charCodeAt()}`);
}
/*
"h----104"
"e----101"
"l----108"
"l----108"
"o----111"
*/

在这里,我们给 fromCharCode() 通报的是字符串 "hello" 中每一个字母的字符编码。

关卡

// 应战一
var falseObject = new Object(false);
console.log(typeof falseObject);             // ???
console.log(falseObject instanceof Object);  // ???
console.log(falseObject instanceof Boolean); // ???
// 应战二
var numberObject = new Object(100);
console.log(typeof numberObject);             // ???
console.log(numberObject instanceof Object);  // ???
console.log(numberObject instanceof Number);  // ???
// 应战三
var stringObject = new Object("abcde");
console.log(typeof stringObject);             // ???
console.log(stringObject instanceof Object);  // ???
console.log(stringObject instanceof String);  // ???
// 应战四,翻转一个字符串
// 提醒:能够运用数组的 reverse() 要领
var reverse = function(str) {
    // 待完成要领体
}
console.log(reverse("hello"));  // "olleh"

更多

关注微信民众号「劼哥舍」复兴「答案」,猎取关卡详解。
关注 https://github.com/stone0090/javascript-lessons,猎取最新动态。

    原文作者:劼哥stone
    原文地址: https://segmentfault.com/a/1190000007290938
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞