在我们深入 面向对象编程之前 ,让我们先回顾一下Javascript的 对象(Object)
任务:给你的 motorBike 对象添加 wheels, engines 和 seats 属性,并且设置他们的数量。
var car = {
"wheels":4,
"engines":1,
"seats":5
};
除了上一种方法外,我们还可以使用构造函数来创建对象。
构造函数 通常使用大写字母开头,以便把自己和其他普通函数区别开。
下面便是一个 构造函数 了:
var Car = function() {
this.wheels = 4;
this.engines = 1;
this.seats = 1;
};
在 构造函数 中, this 指向被此 构造函数 创建出来的 对象 。所以,当我们在 构造函数 中写:
this.wheels = 4;
这时,它创建出来的新对象将带有 wheels 属性,并且赋值为 4.
你可以认为 构造函数 描述了它所创建出来的对象。
让你的 MotorBike 构造函数 描述一个具有 wheels, engines 和 seats 属性的 对象 ,并且为这些属性设置值。
现在,我们把上一节课我们写的 构造函数 在这里用起来!
使用构造函数时,我们通过在它前面使用 new 关键字 来对它进行调用,如下:
var myCar = new Car();
myCar 现在成为了 Car 的一个 实例(instance),它被 构造函数 描述成下面的样子:
{
wheels: 4,
engines: 1,
seats: 1
}
记住:要使用 new 关键字 去调用构造函数。因为只有这样,Javascript才知道这是要去构造一个新 对象 ,并且把构造函数中的 this 指向这个新对象。
现在,当 myCar (即 Car 的一个 实例 )创建后,他可以像普通对象一样被使用,包括创建、访问、修改它的属性等,就像我们使用其他对象一样。如下:
myCar.turboType = "twin";
我们的 myCar 变量现在有了一个 turboType 属性了,且值为 "twin" 。
在编辑器中,使用 Car 这个构造函数去创建一个新的 实例 ,并且把这个实例赋值给 myCar 。
然后给 myCar 创建一个 nickname 属性,且属性值为一个字符串。
我们之前写的 构造函数 很好,但是我们不想总是创建相同的对象,怎么办呢?
为了解决这个问题,我们要向 构造函数 中添加 参数 。像下面这样:
var Car = function(wheels, seats, engines) {
this.wheels = wheels;
this.seats = seats;
this.engines = engines;
};
现在,我们可以在调用 构造函数 时传入一组 参数 了。
var myCar = new Car(6, 3, 1);
这段代码将会使用这一组 参数 来创建出下面的对象:
{
wheels: 6,
seats: 3,
engines: 1
}
现在该你试试了!改动 Car 的 构造函数 ,使它能够通过使用 参数 来为 wheels 、 seats 、 engines 属性进行赋值。
然后调用你刚刚改写过的 构造函数 ,并传入三个 参数 ,我们就能看到创建的新对象赋值给了 myCar 。
对象拥有自己的特征,称为 属性,对象还有自己的函数,称为 方法 。
在前面的课程(构造函数)中,我们使用了 this 指向当前(将要被创建的)对象中的 公有属性 。
我们也可以创建 私有属性 和 私有方法 ,它们两个在对象外部是不可访问的。
为了完成这个任务,我们在 构造函数 中,使用我们熟悉的 var 关键字去创建变量,来替代我们使用 this 创建 属性 。
比如,我们想记录我们的car行驶的 speed ,但是我们希望外面的代码对 speed 的修改只能是加速或减速(而不是变成字符串、直接赋值成某个速度等其他操作),那么如何达到这类操作的目的呢?
编辑器中的 构造函数 展示了如何实现这种控制模式。
该你自己试试了!修改 Bike 的 构造函数 ,使它有一个名为 gear 的 私有属性 ,还有两个公有方法,叫做 getGear 和 setGear ,这两个方法用来获得和设置 gear 的值。
var Car = function() {
// this is a private variable
var speed = 10;
// these are public methods
this.accelerate = function(change) {
speed += change;
};
this.decelerate = function() {
speed -= 5;
};
this.getSpeed = function() {
return speed;
};
};
map 方法可以方便的迭代数组,例子:
var timesFour = oldArray.map(function(val){
return val * 4;
});
map 方法会迭代数组中的每一个元素,并根据回调函数来处理每一个元素,最后返回一个新数组。注意,这个方法不会改变原始数组。
在我们的例子中,回调函数只有一个参数,即数组中元素的值 (val 参数) ,但其实,你的回调函数也可以支持多个参数,譬如:元素的索引index、原始数组arr。
使用 map 方法来为 oldArray 中的每一项增加3,并且在 newArray 中保存它们。 oldArray 不应该被改变。
数组方法 reduce 用来迭代一个数组,并且把它累积到一个值中。
使用 reduce 方法时,你要传入一个回调函数,这个回调函数的参数是一个 累加器 (比如例子中的 previousVal) 和当前值 (currentVal)。
reduce 方法有一个可选的第二参数,它可以被用来设置累加器的初始值。如果没有在这定义初始值,那么初始值将变成数组中的第一项,而 currentVal 将从数组的第二项开始。
下面的例子使用了 reduce 来让数组中的所有值相减:
var singleVal = array.reduce(function(previousVal, currentVal) {
return previousVal - currentVal;
}, 0);
使用 reduce 方法来让 array 中的所有值相加,并且把结果赋值给 singleVal 。
filter 方法用来迭代一个数组,并且按给出的条件过滤出符合的元素。
filter 方法传入一个回调函数,这个回调函数会携带一个参数,参数为当前迭代的项(我们叫它 val )。
回调函数返回 true 的项会保留在数组中,返回 false 的项会被过滤出数组。
下面的代码示例展示了使用 filter 来移除数组中值等于5的项:
注意: 我们忽略了第二参数和第三参数,因为例子中我们只需要第一参数就够了。
array = array.filter(function(val) {
return val !== 5;
});
使用 filter 来创建一个新数组,新数组的值是 oldArray 中值小于6的元素。不许改变原数组 oldArray 。
使用 sort 方法,你可以很容易的按字母顺序或数字顺序对数组中的元素进行排序。
与我们之前用的数组方法仅仅返回一个新数组不同, sort 方法将改变原数组,返回被排序后的数组。
sort 可以把比较函数作为参数传入。比较函数有返回值,当 a 小于 b,返回一个负数;当 a 大于 b ,返回一个正数;相等时返回0。
如果没有传入比较函数,它将把值全部转成字符串,并按照字母顺序进行排序。
下面的例子将展示 sort 的使用,传入的比较函数把元素按照从小到大的顺序进行排列:
var array = [1, 12, 21, 2];
array.sort(function(a, b) {
return a - b;
});
使用 sort 按照从大到小的顺序排序 array 。
你可以使用 reverse 方法来翻转数组。
var myArray = [1, 2, 3];
myArray.reverse();
结果myArray 变成了 [3, 2, 1]
使用 reverse 来翻转 array 数组。并赋值给 newArray.
concat 方法可以用来把两个数组的内容合并到一个数组中。
concat 方法的参数应该是一个数组。参数中的数组会拼接在原数组的后面,并作为一个新数组返回。
下面是一个拼接数组的例子,用concat 把 otherArray 拼接在 oldArray 的后面:
newArray = oldArray.concat(otherArray);
使用 .concat() 将 concatMe 拼接到 oldArray 后面,并且赋值给 newArray。
你可以使用 split 方法按指定分隔符将字符串分割为数组。
你要给 split 方法传递一个参数,这个参数将会作为一个分隔符。
下面的例子展示了 split 方法的使用,按照 s 字母进行分割:
var array = string.split('s');
使用 split 方法来把字符串 string 分割为数组 array。
我们还可以使用 join 方法来把数组转换成字符串,里面的每一个元素可以用你指定的连接符来连接起来,这个连接符就是你要传入的参数。
下面展示了使用 join 来将数组中的每一项放入字符串,并用 and 进行连接:
var veggies = ["Celery", "Radish", "Carrot", "Potato"];
var salad = veggies.join(" and ");
console.log(salad); // "Celery and Radish and Carrot and Potato"
使用 join 方法,连接符为' '把数组 joinMe 转化成字符串 joinedString.
1. Reverse a String 翻转字符串
★ 具体步骤
- 字符串->数组:str.split(“连接符”)
- 翻转数组:arr.reverse(),本方法直接改变原数组
- 数组->字符串:arr.join(“连接符”)
★ 代码
function reverseString(str) {
var arr = new Array();
arr = str.split("");
arr.reverse();
str = arr.join("");
return str;
}
reverseString("hello"); // olleh
2. Factorialize a Number 计算一个整数的阶乘
★ 具体步骤
- 分情况:if 判断 n=0,n>0
- 循环计算:n=0 时,n!=1,n>0 时,循环累乘 n!=1×2×···×n
★ 代码
function factorialize(num) {
var sum = 1;
if (num == 0) {
sum = 1;
}
else {
for (var i = 1; i <= num; i++) {
sum = sum * i;
}
}
return sum;
}
factorialize(5); // 120
3. Check for Palindromes 判断回文
★ 要求
回文(palindrome):一个字符串忽略标点符号、大小写和空格,正着读和反着读一模一样,例如 eye
如果给定的字符串是回文,返回 true,反之,返回 false
★ 思路
去掉字符串多余的标点符号和空格,然后把字符串转化成小写,翻转之后检查是否与原字符串相等
★ 具体步骤
- 用正则表达式找到字符串多余的标点符号和空格(找出字母和数字即可)
- 去除非字母数字符号:str.replace(被替换部分,替换部分)
- 将字符串转为小写:str.toLowerCase()
- 将字符串翻转:见第一题
- 判断翻转后的字符串与原来的是否相同
正则表达式:用来匹配字符串中字符组合的模式。其中 W 表示字母、数字、下划线,因此 [\W_] 就可以表示非字母数字了,也可以用 [^A-Za-z0-9] 表示
★ 代码
function palindrome(str) {
var re = /[\W_]/g;
var newStr = str.replace(re,"").toLowerCase(); // 纯字母数字的小写形式
var reverseStr = newStr.split("").reverse().join("");
return reverseStr == newStr;
}
palindrome("eye"); // true
4. Find the Longest Word in a String 找到提供的句子中最长的单词,并计算它的长度
★ 思路
将字符串转为数组,记录下每个数组元素的长度,将长度排序
★ 具体步骤
- 将字符串转为数组:split()
- 循环:将每个数组元素的长度保存在新数组中
- 排序:将长度数组排序sort(),得到最大长度值
★ 代码
function findLongestWord(str) {
var arr = new Array();
var arrLen = new Array();
arr = str.split(" ");
for (var i = 0; i < arr.length; i++){
arrLen[i] = arr[i].length;
}
arrLen.sort(function(a,b) {
return b-a;
});
return arrLen[0];
}
findLongestWord("The quick brown fox jumped over the lazy dog"); // 6
5. Title Case a Sentence 字符串的单词首字母大写其余小写
★ 思路
先将所有字母统一为小写,再将字符串转化为数组,将每一个数组元素的第一个字符变为大写
★ 具体步骤
- 转小写:将字符串中所有字母转为小写 str.toLowerCase()
- 字符串->数组:str.split()
- 遍历数组,将每个数组元素第一个字母替换为大写
遍历 arr.map()
替换 arr.replace()
单字符 arr.charAt(index)
大写 toUpperCase() - 数组->字符串:arr.join()
★ 代码
function titleCase(str) {
str = str.toLowerCase();
var arr = new Array();
arr = str.split(" ");
var newArr = new Array();
newArr = arr.map(toUpper);
function toUpper(element) {
return element.replace(element.charAt(0),element.charAt(0).toUpperCase());
}
str = newArr.join(" ");
return str;
}
titleCase("I'm a little tea pot"); // I'm A Little Tea Pot
6. Return Largest Numbers in Arrays 将小数组们的最大值串联成新数组
★ 要求
大数组中包含了若干个小数组,分别找到每个小数组中的最大值(数值的最大值),然后把它们串联起来,形成一个新数组
★ 具体步骤
- 先把大数组分为若干小数组
- 循环小数组中每一个元素
- 找到每个小数组中的最大值
- 用新数组存储最大值
★ 代码
function largestOfFour(arr) {
var newArr = new Array();
for (var i = 0; i < arr.length; i++) {
var max = arr[i][0]; // max 要定义在内层循环外
for (var j = 0; j < arr[i].length; j++) {
if (arr[i][j] >= max) {
max = arr[i][j];
}
}
newArr[i] = max;
}
return newArr;
}
largestOfFour([[4,5,1,3],[13,27,18,26],[32,35,37,39],[1000,10001,857,1]]); // [5,27,39,10001]
7. Confirm the Ending 检查一个字符串是否以指定的字符串结尾
★ 思路
首先要知道指定字符串 target 的个数,找到待检查字符串中最后几位,判断两者是否相等
★ 具体步骤
str.substr(beginindex,endindex) 方法:返回字符串从指定位置开始,到指定长度的字符串
★ 代码
function confirmEnding(str,target) {
return target == str.substr(str.length-target.length,target.length);
}
confirmEnding("Bastian","n"); // true
8. Repeat a string repeat a string 重要的事情说3遍
★ 要求
重复一个指定的字符串 num 次,如果 num 是一个负数则返回一个空字符串
★ 具体步骤
- 保留原始字符串:var newStr = str
- 循环
★ 代码
function repeat(str,num) {
var newStr = str;
if (num > 0) {
for (var i = 0; i < num; i++) {
newStr = newStr.concat(str);
}
}
else {
newStr = "";
}
return newStr;
}
repeat("abc",3); // abcabcabcabc
9. Truncate a string 用瑞兹来截断对面的退路
★ 要求
如果字符串的长度比指定的参数num长,则把多余的部分用…来表示
切记,插入到字符串尾部的三个点号也会计入字符串的长度
但是,如果指定的参数num小于或等于3,则添加的三个点号不会计入字符串的长度
★ 思路
最开始要判断 num 是否大于字符串长度,当 num 小于字符串长度时,分 num 小于等于 3 和大于 3 的情况,当 num<=3 时,直接在字符串后面加三个点;当 num> 3时,字符串 + 三个点的长度 =num
★ 具体步骤
- num<=3:str.slice()、str.concat(“…”)
- num>3:str.slice()、str.concat(“…”)
★ 代码
function truncate(str,num) {
var newStr;
if (num < str.length) {
if (num <= 3) {
newStr = str.slice(0,num);
newStr = newStr.concat("...");
}
else {
newStr = str.slice(0,num-3);
newStr = newStr.concat("...");
}
}
else {
newStr = str;
}
return newStr;
}
truncate("A-tisket a-tasket A green and yellow basket","A-tisket a-tasket A green and yellow basket".length+2); // A-tisket a-tasket A green and yellow basket
10. Chunky Monkey 猴子吃香蕉可是掰成好几段来吃哦
★ 要求
把一个数组 arr 按照指定的数组大小 size 分割成若干个数组块
★ 思路
将分割出的数组块当作一个个数组元素存在一个新的数组中,要确定分割的个数,才好循环
★ 具体步骤
设定切割起始位置 begin 与 end,并按照 size 大小累加,将切下的数组块循环 push 进新数组中
arr.slice(beginindex,endindex),切割时包括 beginindex,不包括 endindex
注意arr.push() 返回的是长度值
★ 代码
function chunk(arr,size) {
var newArr = new Array();
var begin = 0;
var end = size;
for (var i = 0; i < arr.length/size; i++) {
newArr.push(arr.slice(begin,end));
begin = begin + size;
end = end + size;
}
return newArr;
}
chunk(["a","b","c","d","e"],2); // [["a","b"],["c","d"]["e"]]
11. Slasher Flick 打不死的小强
★ 要求
返回一个数组被截断 n 个元素后还剩余的元素,截断从索引 0 开始(删除数组前 n 个元素)
★ 具体步骤
array.splice(start, deleteCount[, item1[, item2[, …]]])
start 为开始索引值,deleteCount 为整数,表示要移出的元素个数,item1 表示要添加的元素,若无,则函数只删除元素。函数返回被删除元素数组
★ 代码
function slasher(arr,howMany) {
return arr.splice(howMany,arr.length-howMany);
}
slasher([1,2,3],2); // [3]
12. Mutations 蛤蟆可以吃队友,也可以吃对手
★ 要求
如果数组第一个字符串元素包含了第二个字符串元素的所有字符,忽略顺序和大小写,函数返回 true
例如:["hello", "hey"] 应该返回 false,因为字符串 "hello" 并不包含字符 "y"
再例如:["Alien", "line"] 应该返回 true,因为 "line" 中所有字符都可以在 "Alien" 找到
★ 思路
首先要将两个字符串统一为小写,再看第二个字符串中的所有元素是不是都能在第一个字符串中找到
★ 具体步骤
- 数组->字符串:个数较少,直接用下标赋值
- 字符串转小写:str.toLowerCase()
- 第二个字符串->数组:str.split()
- 检查第二个字符串中的每个字符是否都能在第一个字符串中找到
★ 代码
function mutation(arr) {
var str1 = arr[0].toLowerCase();
var str2 = arr[1].toLowerCase();
var arr2 = new Array();
arr2 = str2.split("");
for (var i = 0; i < arr2.length; i++) {
if (str1.indexOf(arr2[i]) == -1) {
return false;
}
else {
continue;
}
}
return true;
}
mutation(["hello","hey"]); // false
13. Falsy Bouncer 真假美猴王
★ 要求
删除数组中的所有假值
在JavaScript中,假值有 false、null、0、”“、undefined 和 NaN
★ 思路
遍历数组,判断是否为假值,是则删除,否则留下
★ 具体步骤
- 遍历数组:arr.filter()
- 判断是否为假值:Boolean(element)。element 为假值返回 false,真值返回 true
★ 代码
function bouncer(arr) {
var newArr = arr.fliter(delFalsy);
function delFalsy(element) {
return Boolean(element);
}
return newArr;
}
bouncer([7,"ate","",false,9]); // [7,”ate",9]
return arr.filter(Boolean);
14. Seek and Destroy 金克斯的迫击炮
★ 要求
实现一个摧毁 destroyer 函数,第一个参数是待摧毁的数组,其余的参数是待摧毁的值
例如:destroyer([1, 2, 3, 1, 2, 3], 2, 3) 应该返回 [1, 1]
★ 思路
遍历数组,将与待摧毁值相同的数组元素删除
★ 具体步骤
- 将待摧毁值存入一个数组中:arguments[index]
- 遍历数组:arr.filter()
- 判断是否要摧毁:循环+判断
★ 注意
- filter 是根据其函数返回值判断是否保留该元素,true 为保留,false 为删除。注意循环的结束与跳过情况
- arguments[index] 不要放在内部函数中,这样将取不到外部函数的参数
- 循环中最好不要调用函数
★ 代码
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments, 1);
return arr.filter(function(value){
return !args.includes(value);
});
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
15. Where do I belong 我身在何处
★ 要求
先给数组排序,然后找到指定的值在数组的位置,最后返回位置对应的索引
例如:where([1,2,3,4], 1.5) 返回 1
因为 1.5 插入到数组 [1,2,3,4] 后变成 [1,1.5,2,3,4],而 1.5 对应的索引值就是 1
★ 具体步骤
- 指定元素放入数组:arr.push()
- 数组排序:从小到大 arr.sort()
- 找到指定元素的索引:arr.indexOf()
★ 代码
function where(arr,num) {
arr.push(num);
arr.sort(function(a,b) {
return a-b; // 从小到大
});
return arr.indexOf(num);
}
where([40,60],50); // 1
16. Caesars Cipher 让上帝的归上帝,凯撒的归凯撒(凯撒编码)
★ 要求
写一个 ROT13 函数,实现输入加密字符串,输出解密字符串。注意:所有的字母都是大写,不要转化任何非字母形式的字符(例如:空格,标点符号),遇到这些特殊字符,跳过它们
ROT13:http://www.baike.com/wiki/ROT13&prd=so_1_doc
★ 思路
将 A-M 的 Unicode 值 +13,将 N-Z 的 Unicode 值-13
★ 具体步骤
- 得到字符串中每个字母的 Unicode(UTF16) 值:str.charCodeAt(index) 返回 0~65535 之间的整数
- 将 A-M 的 Unicode 值 +13,将 N-Z 的 Unicode 值 -13,其余字符不变
- Unicode值->字母:String.fromCharCode(Unicode值)
★ 代码
function rot13(str) {
var arr = new Array();
for (var i = 0; i < str.length; i++) {
var utfNum = str.charCodeAt(i);
if (utfNum >= 65 && utfNum <= 90) {
if (utfNum <= 77) {
utfNum += 13;
}
else {
utfNum -= 13;
}
}
arr[i] = String.fromCharCode(utfNum);
}
str = arr.join("");
return str;
}
rot13("SERR CVMMN!"); // "FREE PIZZA!"