一、操作符

1.一元操作符

自加自减操作符

前置型

执行前置递增和递减操作时,变量的值都是在语句被求值以前改变的

var num1 = 2;
var num2 = 20;
var num3 = --num1 + num2; // 等于 21
var num4 = num1 + num2; // 等于 21

后置型

把递增操作符放在变量后面并不会改变语句的结果

var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2; // 等于 22
var num4 = num1 + num2; // 等于 21

在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,再执行加减 1 的操作。字
符串变量变成数值变量。
 在应用于一个不包含有效数字字符的字符串时,将变量的值设置为 NaN(第 4 章将详细讨论)。
字符串变量变成数值变量。
 在应用于布尔值 false 时,先将其转换为 0 再执行加减 1 的操作。布尔值变量变成数值变量。
 在应用于布尔值 true 时,先将其转换为 1 再执行加减 1 的操作。布尔值变量变成数值变量。
 在应用于浮点数值时,执行加减 1 的操作。
 在应用于对象时,先调用对象的 valueOf()方法(第 5 章将详细讨论)以取得一个可供操作的
值。然后对该值应用前述规则。如果结果是 NaN,则在调用 toString()方法后再应用前述规
则。对象变量变成数值变量

var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1++; // 值变成数值 3
s2++; // 值变成 NaN
b++; // 值变成数值 1
f--; // 值变成 0.10000000000000009(由于浮点舍入错误所致)
o--; // 值变成数值-2

加和减操作符

一元加操作符以一个加号(+)表示,放在数值前面,对数值不会产生任何影响,

var num = 25;
num = +num; // 仍然是 25

不过,在对非数值应用一元加操作符时,该操作符会像 Number()转型函数一样对这个值执行转换

var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = +s1; // 值变成数值 1
s2 = +s2; // 值变成数值 1.1
s3 = +s3; // 值变成 NaN
b = +b; // 值变成数值 0
f = +f; // 值未变,仍然是 1.1
o = +o; // 值变成数值-1

一元减操作符主要用于表示负数

var num = 25;
num = -num; // 变成了-25

当应用于非数值时,一元减操作符遵循与一元加操作符相同的规则,最后再将得到的数值转换为负数

var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
valueOf: function() {
return -1;
}
};
s1 = -s1; // 值变成了数值-1
s2 = -s2; // 值变成了数值-1.1
s3 = -s3; // 值变成了 NaN
b = -b; // 值变成了数值 0
f = -f; // 变成了-1.1
o = -o; // 值变成了数值 1

2.位操作符

暂略

3.布尔操作符

逻辑非(!)

无论这个值是什么数据类型,这个操作符都会返回一个布尔值。逻辑非操作符首先会将它的操作数转换为一个布尔值,然后再对其求反

 如果操作数是一个对象,返回 false;
 如果操作数是一个空字符串,返回 true;
 如果操作数是一个非空字符串,返回 false;
 如果操作数是数值 0,返回 true;
 如果操作数是任意非 0 数值(包括 Infinity),返回 false;
 如果操作数是 null,返回 true;
 如果操作数是 NaN,返回 true;
 如果操作数是 undefined,返回 true。

alert(!false); // true
alert(!"blue"); // false
alert(!0); // true
alert(!NaN); // true
alert(!""); // true
alert(!12345); // false

同时使用两个逻辑非操作符,实际上就会模拟 Boolean()转型函数的行为

alert(!!"blue"); //true
alert(!!0); //false
alert(!!NaN); //false
alert(!!""); //false
alert(!!12345); //true

逻辑与(&&)

逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值

 如果第一个操作数是对象,则返回第二个操作数;
 如果第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该
对象;
 如果两个操作数都是对象,则返回第二个操作数;
 如果有一个操作数是 null,则返回 null;
 如果有一个操作数是 NaN,则返回 NaN;
 如果有一个操作数是 undefined,则返回 undefined。

如果第一个操作数是 false,则无论第二个操作数是什么值,结果都不再可能是true 了

var found = true;
var result = (found && someUndefinedVariable); // 这里会发生错误
alert(result); // 这一行不会执行
var found = false;
var result = (found && someUndefinedVariable); // 不会发生错误
alert(result); // 会执行( "false")

逻辑或

与逻辑与操作相似,如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值

 如果第一个操作数是对象,则返回第一个操作数;
 如果第一个操作数的求值结果为 false,则返回第二个操作数;
 如果两个操作数都是对象,则返回第一个操作数;
 如果两个操作数都是 null,则返回 null;
 如果两个操作数都是 NaN,则返回 NaN;
 如果两个操作数都是 undefined,则返回 undefined

与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为
true,就不会对第二个操作数求值了

var found = true;
var result = (found || someUndefinedVariable); // 不会发生错误
alert(result); // 会执行( "true")

4.乘性操作符

乘法

var result = 34 * 56;

在处理特殊值的情况下,乘法操作符遵循下列特殊的规则:
 如果操作数都是数值,执行常规的乘法计算,即两个正数或两个负数相乘的结果还是正数,而
如果只有一个操作数有符号,那么结果就是负数。如果乘积超过了 ECMAScript 数值的表示范围,
则返回 Infinity 或-Infinity;
 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 与 0 相乘,则结果是 NaN;
 如果是 Infinity 与非 0 数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数
的符号;
 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的
规则。

除法

var result = 66 / 11;

 如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而
如果只有一个操作数有符号,那么结果就是负数。如果商超过了 ECMAScript 数值的表示范围,
则返回 Infinity 或-Infinity;
 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 被 Infinity 除,则结果是 NaN;
 如果是零被零除,则结果是 NaN;
 如果是非零的有限数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
 如果是 Infinity 被任何非零数值除,则结果是 Infinity 或-Infinity,取决于有符号操作
数的符号;

 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。

求余

var result = 26 % 5; // 等于 1

与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则来处理特殊的值:
 如果操作数都是数值,执行常规的除法计算,返回除得的余数;
 如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN;
 如果被除数是有限大的数值而除数是零,则结果是 NaN;
 如果是 Infinity 被 Infinity 除,则结果是 NaN;
 如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
 如果被除数是零,则结果是零;
 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则

5.加性操作符

var result = 1 + 2;

 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 加 Infinity,则结果是 Infinity;
 如果是-Infinity 加-Infinity,则结果是-Infinity;
 如果是 Infinity 加-Infinity,则结果是 NaN;
 如果是+0 加+0,则结果是+0;
 如果是0 加0,则结果是0;
 如果是+0 加0,则结果是+0。
不过,如果有一个操作数是字符串,那么就要应用如下规则:
 如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接
起来。

如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值,
然后再应用前面关于字符串的规则。对于 undefined 和 null,则分别调用 String()函数并取得字符
串"undefined"和"null"

var result1 = 5 + 5; // 两个数值相加
alert(result1); //
var result2 = 5 + "5"; // 一个数值和一个字符串相加
alert(result2); // "55"
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + num1 + num2;
alert(message); // "The sum of 5 and 10 is 510"
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is " + (num1 + num2);
alert(message); //"The sum of 5 and 10 is 15"

减法

var result = 2 - 1;

 如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;
 如果有一个操作数是 NaN,则结果是 NaN;
 如果是 Infinity 减 Infinity,则结果是 NaN;
 如果是-Infinity 减-Infinity,则结果是 NaN;
 如果是 Infinity 减-Infinity,则结果是 Infinity;
 如果是-Infinity 减 Infinity,则结果是-Infinity;
 如果是+0 减+0,则结果是+0;
 如果是+0 减0,则结果是0;

 如果是0 减0,则结果是+0;
 如果有一个操作数是字符串、布尔值、 null 或 undefined,则先在后台调用 Number()函数将
其转换为数值,然后再根据前面的规则执行减法计算。如果转换的结果是 NaN,则减法的结果
就是 NaN;
 如果有一个操作数是对象,则调用对象的 valueOf()方法以取得表示该对象的数值。如果得到
的值是 NaN,则减法的结果就是 NaN。如果对象没有 valueOf()方法,则调用其 toString()
方法并将得到的字符串转换为数值

var result1 = 5 - true; // 4,因为 true 被转换成了 1
var result2 = NaN - 1; // NaN
var result3 = 5 - 3; //
var result4 = 5 - ""; // 5,因为"" 被转换成了 0
var result5 = 5 - "2"; // 3,因为"2"被转换成了 2
var result6 = 5 - null; // 5,因为 null 被转换成了 0

6.关系操作符

小于(<) 、大于(>) 、小于等于(<=)和大于等于(>=)再应用上面的规则。这几个操作符都返回一个布尔值

var result1 = 5 > 3; //true
var result2 = 5 < 3; //false

 如果两个操作数都是数值,则执行数值比较。
 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
 如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执
行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面
的规则执行比较。
 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。

在比较字符串时,实际比较的是两个字符串中对应位置的每个字符的字符编码值。经过这么一番比较之后,再返回一个布尔值

var result = "Brick" < "alphabet"; //true
var result = "23" < "3"; //true

在比较数值和字符串时,字符串都会被转换成数值,然后再以数值方式与另一个数值比较

var result = "23" < 3; //false

如果那个字符串不能被转换成一个合理的数值

var result = "a" < 3; // false,因为"a"被转换成了 NaN

任何操作数与 NaN 进行关系比较,结果都是 false

var result1 = NaN < 3; //false
var result2 = NaN >= 3; //false

7.相等操作符

相等和不相等

如果两个操作数相等,则返回 true ,两个操作数不相等,则返回 false

两个操作符都会先转换操作数(通常称为强制转型),然后再比较它们的相等性

在转换不同的数据类型时的基本规则 :

 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值——false 转换为 0,而
true 转换为 1;

 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;
 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类
型值按照前面的规则进行比较;
这两个操作符在进行比较时则要遵循下列规则。
 null 和 undefined 是相等的。
 要比较相等性之前,不能将 null 和 undefined 转换成其他任何值。
 如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。重要提示:
即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则, NaN 不等于 NaN。
 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,
则相等操作符返回 true;否则,返回 false

 全等和不全等

除了在比较之前不转换操作数之外,全等和不全等操作符与相等和不相等操作符没有什么区别。全等操作符由 3 个等于号(===)表示,它只在两个操作数未经转换就相等的情况下返回 true

var result1 = ("55" == 55); //true,因为转换后相等
var result2 = ("55" === 55); //false,因为不同的数据类型不相等
var result1 = ("55" != 55); //false,因为转换后相等
var result2 = ("55" !== 55); //true,因为不同的数据类型不相等

***  null == undefined 会返回 true,因为它们是类似的值;但 null === undefined 会返回 false,因为它们是不同类型的值

8.条件操作符

var max = (num1 > num2) ? num1 : num2;

如果num1 > num2 为真,返回num1

如果num1 > num2 为假,返回num2

9.赋值操作符

如果在等于号(=)前面再添加乘性操作符、加性操作符或位操作符,就可以完成复合赋值操作

num += 10;
//相当于
num = num + 10;

 乘/赋值(*=);
 除/赋值(/=);
 模/赋值(%=);
 加/赋值(+=);
 减/赋值(=);
 左移/赋值(<<=);
 有符号右移/赋值(>>=)
 无符号右移/赋值(>>>=)

10.逗号操作符

使用逗号操作符可以在一条语句中执行多个操作

var num1=1, num2=2, num3=3;

在用于赋值时,逗号操作符总会返回表达式中的最后一项

var num = (5, 1, 4, 8, 0); // num 的值为 0

虽然逗号的这种使用方式并不常见,但这个例子可以帮我们理解逗号的这种行为

二、语句

1.if语句

if (i > ) {
alert("Greater than 25.");
} else if (i < ) {
alert("Less than 0.");
} else {
alert("Between 0 and 25, inclusive.");
}

2.do-while语句

var i = ;
do {
i += ;
} while (i < );
alert(i);

3.while语句

var i = ;
while (i < ) {
i += ;
}

4.for语句

var count = ;
for (var i = ; i < count; i++){
alert(i);
}

5.for in 语句

for-in 语句是一种精准的迭代语句,可以用来枚举对象的属性

for (var propName in window) {
document.write(propName);
}

使用 for-in 循环来显示了 BOM 中 window 对象的所有属性

6.label语句

使用 label 语句可以在代码中添加标签,当break label 或 continue label  会跳到标签位置

start: for (var i=; i < count; i++) {
alert(i);
}

这个例子中定义的 start 标签可以在将来由 break 或 continue 语句引用。加标签的语句一般都
要与 for 语句等循环语句配合使用

7.break和continue语句

break跳出本层循环

var num = ;
for (var i=; i < ; i++) {
if (i % == ) {
break;
}
num++;
}
alert(num); //

continue跳出本次循环

var num = ;
for (var i=; i < ; i++) {
if (i % == ) {
continue;
}
num++;
}
alert(num); //

配合label使用

var num = ;
outermost:
for (var i=; i < ; i++) {
for (var j=; j < ; j++) {
if (i == && j == ) {
break outermost;
}
num++;
}
}
alert(num); //

建议如果使用 label 语句,一定要使用描述性的标签,同时不要嵌套过多的循环

8.with语句

不建议使用

9.switch语句

switch (i) {
case :
alert("");
break;
case :
alert("");
break;
case :
alert("");
break;
default:
alert("Other");
}
合并两种情形
switch (i) {
case :
/* 合并两种情形 */
case :
alert("25 or 35");
break;
case :
alert("");
break;
default:
alert("Other");
}
var num = ;
switch (true) {
case num < :
alert("Less than 0.");
break;
case num >= && num <= :
alert("Between 0 and 10.");
break;
case num > && num <= :
alert("Between 10 and 20.");
break;
default:
alert("More than 20.");
}

三、函数

定义函数

function sayHi(name, message) {
alert("Hello " + name + "," + message);
}

调用函数

sayHi("Nicholas", "how are you today?");

ECMAScript 中的函数在定义时不必指定是否返回值

理解参数

ECMAScript 函数的参数与大多数其他语言中函数的参数有所不同。 ECMAScript 函数不介意传递进
来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,
在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而解析器永远不
会有什么怨言。之所以会这样,原因是 ECMAScript 中的参数在内部是用一个数组来表示的。函数接收
到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任
何元素,无所谓;如果包含多个元素,也没有问题。实际上,在函数体内可以通过 arguments 对象来
访问这个参数数组,从而获取传递给函数的每一个参数。
其实, arguments 对象只是与数组类似(它并不是 Array 的实例),因为可以使用方括号语法访
问它的每一个元素(即第一个元素是 arguments[0],第二个元素是 argumetns[1],以此类推),使
用 length 属性来确定传递进来多少个参数。在前面的例子中, sayHi()函数的第一个参数的名字叫
name,而该参数的值也可以通过访问 arguments[0]来获取。因此,那个函数也可以像下面这样重写,
即不显式地使用命名参数:

function sayHi() {
alert("Hello " + arguments[0] + "," + arguments[1]);
}
FunctionExample05.

这个重写后的函数中不包含命名的参数。虽然没有使用 name 和 message 标识符,但函数的功能
依旧。这个事实说明了 ECMAScript 函数的一个重要特点:命名的参数只提供便利,但不是必需的。另
外,在命名参数方面,其他语言可能需要事先创建一个函数签名,而将来的调用必须与该签名一致。但
在 ECMAScript 中,没有这些条条框框,解析器不会验证命名参数。

通过访问 arguments 对象的 length 属性可以获知有多少个参数传递给了函数。下面这个函数会
在每次被调用时,输出传入其中的参数个数:

function howManyArgs() {
alert(arguments.length);
}
howManyArgs("string", 45); //
howManyArgs(); //
howManyArgs(12); //
function doAdd() {
if(arguments.length == 1) {
alert(arguments[0] + 10);
} else if (arguments.length == 2) {
alert(arguments[0] + arguments[1]);
}
}
doAdd(10); //
doAdd(30, 20); //

没有重载

如果在 ECMAScript 中定义了两个名字相同的函数,则该名字只属于后定义的函数

function addSomeNumber(num){
return num + 100;
}
function addSomeNumber(num) {
return num + 200;
}
var result = addSomeNumber(100); //

(2)JavaScript基础2的更多相关文章

  1. JavaScript基础

    JavaScript基础 JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的处 ...

  2. 一步步学习javascript基础篇(0):开篇索引

    索引: 一步步学习javascript基础篇(1):基本概念 一步步学习javascript基础篇(2):作用域和作用域链 一步步学习javascript基础篇(3):Object.Function等 ...

  3. 前端之JavaScript基础

    前端之JavaScript基础 本节内容 JS概述 JS基础语法 JS循环控制 ECMA对象 BOM对象 DOM对象 1. JS概述 1.1. javascript历史 1992年Nombas开发出C ...

  4. 一步步学习javascript基础篇(3):Object、Function等引用类型

    我们在<一步步学习javascript基础篇(1):基本概念>中简单的介绍了五种基本数据类型Undefined.Null.Boolean.Number和String.今天我们主要介绍下复杂 ...

  5. Javascript基础回顾 之(三) 面向对象

    本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Javascript的一些基本原理普遍存在这里或者 ...

  6. Javascript基础回顾 之(二) 作用域

    本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Javascript的一些基本原理普遍存在这里或者 ...

  7. Javascript基础回顾 之(一) 类型

    本来是要继续由浅入深表达式系列最后一篇的,但是最近团队突然就忙起来了,从来没有过的忙!不过喜欢表达式的朋友请放心,已经在写了:) 在工作当中发现大家对Javascript的一些基本原理普遍存在这里或者 ...

  8. JavaScript 基础回顾——对象

    JavaScript是基于对象的解释性语言,全部数据都是对象.在 JavaScript 中并没有 class 的概念,但是可以通过对象和类的模拟来实现面向对象编程. 1.对象 在JavaScript中 ...

  9. javascript基础01

    javascript基础01 Javascript能做些什么? 给予页面灵魂,让页面可以动起来,包括动态的数据,动态的标签,动态的样式等等. 如实现到轮播图.拖拽.放大镜等,而动态的数据就好比不像没有 ...

  10. javascript基础02

    javascript基础02 1.数据类型 数据类型的描述在上篇的扩展中有写到链接 由于ECMAScript数据类型具有动态性,因此的确没有再定义其他数据类型的必要.这句话很重要. 如果以后再数据类型 ...

随机推荐

  1. 最小生成树:POJ1251-Jungle Roads(最小生成树的模板)

    POJ 1251 Jungle Roads >[poj原址:http://poj.org/problem?id=1251](http://poj.org/problem?id=1251) Des ...

  2. kafka 的offset的重置

    最近在spark读取kafka消息时,每次读取都会从kafka最新的offset读取.但是如果数据丢失,如果在使用Kafka来分发消息,在数据处理的过程中可能会出现处理程序出异常或者是其它的错误,会造 ...

  3. P2485 [SDOI2011]计算器

    P2485 [SDOI2011]计算器 题目描述 你被要求设计一个计算器完成以下三项任务: 1.给定y.z.p,计算y^z mod p 的值: 2.给定y.z.p,计算满足xy ≡z(mod p)的最 ...

  4. redis 之相关命令

    为什么缓存数据库更要首选redis?如何使用redis? 一.使用缓存数据库为什么首选用redis? 我们都知道,把一些热数据存到缓存中可以极大的提高速度,那么问题来了,是用Redis好还是Memca ...

  5. day20 Django Models 操作,多表,多对多

    1 Django models 获取数据的三种方式: 实践: viwes def business(request): v1 = models.Business.objects.all() v2 = ...

  6. BugKu 2B+基于python的opencv的安装-------CTF 盲水印的套路

    BugKu杂项-2B 下载图片后,binwalk下跑一跑,发现有个zip,分离. 值得一提的是,这个zip是伪加密的. 但是你在分离的时候,伪加密的图片也给你分离出来了.这两个图片2B和B2肉眼看起来 ...

  7. python week09 Mysql 数据库基础知识

    第一篇:初识数据库 注:<基础概念,不再赘述,点开链接查看> 第二篇:库相关操作 一 系统数据库 information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些 ...

  8. python re 模块小结

    前言: 本人环境windows 7 64位,python2.7 re是什么: regular expression缩写,意为正则表达式,是python的众多模块之一 re用途: 从文本中有选择的批量抽 ...

  9. Leetcode 655.输出二叉树

    输出二叉树 在一个 m*n 的二维字符串数组中输出二叉树,并遵守以下规则: 行数 m 应当等于给定二叉树的高度. 列数 n 应当总是奇数. 根节点的值(以字符串格式给出)应当放在可放置的第一行正中间. ...

  10. LeetCode——Problem3:Longest Substring Without Repeating Characters

    哎哟我天啊.这道题快折磨死我了.刚开始连题都没看明白,就是不知道substring是什么意思.研究了好长时间才看出来的. 光辉历史呀...菜死了 1.题目 Given a string, find t ...