var str = "abcdefghijk";
console.log(str.split('').reverse().join(''))
//输出:kjihgfedcba
split()将字符串变成数组,reverse()将数组翻转,join将数组变成字符串
var str = "abcdabcaba"; //给定字符串
var strArr = str.split(""); //将字符串分割成数组
var NewArr = []; //创建新数组,用来保存去重后的值
for (let i in strArr) { //切记使用let声明,let证明的变量只在当前作用域中生效
if (NewArr.indexOf(strArr[i]) == -1) {
//indexOf()判断指定值在数组中的下标,如果等于 - 1 这说明该数组中没有这个值
NewArr.push(strArr[i])
//NewArr中没有这个值就把这个值添加进来,组成新数组,也就是去重数组
}
}
console.log(NewArr);
//输出:["a", "b", "c", "d"]
数组去重的本质是利用 indexOf 检测新数组中是否存在被去重数组中的值,没有的话就加入,有的话就进行下一次循环。
var Arr = ["a", "a", "a", "a", "b", "c", "d", "e", "f", "g", "k", "l"];
var newArr = new Set(Arr)
console.log([...newArr]);
//ES6 新增 Set 方法
//Set类似于数组(但不是数组所以要把它转化成数组),区别在于它所有的成员都是唯一的,不能有重复的值
数组去重的衍生,有两个小写字符串str1 、str2 。str2 是 str1 经过打乱后增加几个小写字符得到的, 编程得出s2中增加的字符
var str1 = "abcdefg"
//["a", "b", "c", "d", "e", "f", "g"]
var str2 = "caflkebgdaaa"
//["a", "a", "a", "a", "b", "c", "d", "e", "f", "g", "k", "l"]
var newstr1 = str1.split("").sort();
var newstr2 = str2.split("").sort();
var tempArr = [];
for(let i in newstr2){
if(newstr1.indexOf(newstr2[i]) == -1){
tempArr.push(newstr2[i]) ;
}
else{
newstr1.splice(0,1);
//splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。
//arrayObject.splice(index,howmany,item1,.....,itemX)
//splice() 参数,index表示删除的位置索引,howmany表示往索引后删除几个
}
}
console.log(tempArr);
//["a", "a", "a", "k", "l"]
二分法查找,是一种在有序数组中查找特定元素的搜索算法。查找过程可以分为以下步骤:
(1)首先,从有序数组的中间的元素开始搜索,如果该元素正好是目标元素(即要查找的元素),则搜索过程结束,否则进行下一步。
(2)如果目标元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半区域查找,然后重复第一步的操作。
(3)如果某一步数组为空,则表示找不到目标元素。
//非递归算法
function binary_search(arr, key) { //传入参数,要查找的有序数组,要查找的值
var low = 0, //设置最左端查找区间的值
high = arr.length - 1; //设置最右端查找区间的值
while(low <= high){ //左边小于右边时
var mid = parseInt((high + low) / 2); //设置二分查找的中间值
if(key == arr[mid]){ //如果要查找的值 == 数组中间值
return mid; //返回值,并结束循环
}else if(key > arr[mid]){ //如果要查找的值 > 数组中间值,说明要查找的值在数组右半边
low = mid + 1; //设置最左端查找区间的值 设置为中间值+1,从右侧开始查找
}else if(key < arr[mid]){ //如果要查找的值 < 数组中间值,说明要查找的值在数组右半边
high = mid -1; //设置最右端查找区间的值 设置为中间值-1,从左侧开始查找
}else{
return -1; //整个数组都没找到,返回 -1 并结束循环
}
}
};
var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
var result = binary_search(arr,10);
console.log(result); // 9 (9为目标元素的索引值 )
// 递归算法,其实就是代替了while循环
function binary_search(arr,low, high, key) {
if (low > high){
return -1;
}
var mid = parseInt((high + low) / 2);
if(arr[mid] == key){
return mid;
}else if (arr[mid] > key){
high = mid - 1;
return binary_search(arr, low, high, key);
}else if (arr[mid] < key){
low = mid + 1;
return binary_search(arr, low, high, key);
}
};
var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
var result = binary_search(arr, 0, 13, 10);
console.log(result); // 9 返回目标元素的索引值
什么是闭包?闭包的定义:闭包是指有权访问另外一个函数作用域 中的变量的函数,可以理解为(能够读取其他函数内部变量的函数)
闭包的作用: 正常函数执行完毕后,里面声明的变量被垃圾回收处理掉,但是闭包可以让作用域里的变量,在函数执行完之后依旧保持没有被垃圾回收处理掉
闭包的优点:
1 . 避免全局变量的污染。
2 . 可以实现私有成员的存在。
3 . 可以使一个变量长期存储在内存中。
闭包的缺点:
1 . 常驻内存,增加内存使用量。
2 . 使用不当会很容易造成内存泄露。
// 创建闭包最常见的方式函数作为返回值,举个最经典例子,计数器的例子
function outAdd() {
var counter = 0; //函数内部定义变量,不能被函数外访问到
function innerAdd() { //这里的 innerAdd 就是我们所谓的闭包
return counter += 1;
}
return innerAdd; //返回整个函数,注意千万不能加()
}
var add = outAdd(); //注意这里为什么要将 outAdd 赋值给一个变量(重点)
add(); // 1
add(); // 2
add(); // 3
add(); // 4
这样在执行完 add = outAdd()后,变量 add 实际上是指向了函数 innerAdd,innerAdd 中用到了变量counter ,再执行 add () 后就会显示 counter 的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数 outAdd 外的变量 add 引用了函数 outAdd 内的函数 innerAdd 。
他一共运行 4 次,第一次值 1,第二次值为 2,这就说明 counter 一直在内存中,而不是在第一次 outAdd 函数调用之后就自动清除。
console.log(a) // undefined
var a = 1;
var getNum = function () {
a = 2;
}
function getNum() {
a = 3;
}
console.log(a) // 1
getNum()
console.log(a) // 2
这题主要考察变量提升和函数声明优先于变量声明
// JS预解析阶段,变量提升,且函数提升优先于变量提升
function getNum() {
a = 3;
}
var a; //实质为var a = undefined;
var getNum; //实质为var getNum = undefined;
// 执行代码
console.log(a); //输出undefined
a = 1; //实质为var a = undefined;变成 var a = 1;
//实质执行了var getNum = function(){a=2};
//由于变量声明无法覆盖函数声明,一开始getNum指向一个函数,后来赋值成了一个函数表达式,指向了另一个函数。
getNum = function () {
a = 2;
}
console.log(a) //此时 a 变成了 1
getNum() //执行getNum函数
console.log(a) //此时函数指向已改变,输出 a = 2
for (var i = 0; i < 5; i++) {
setTimeout(function (i) {
console.log(i)
}, i * 1000, i) //setTimeout()的三个参数,第一个为需要延迟执行的代码段
//第二个参数为延迟多久执行,单位毫秒1000ms = 1s
//第三个参数为传递到延迟执行代码段中的参数
}
for(let i = 1; i < 5; i++) {
setTimeout(function(){
console.log(i)
}, i * 1000)
}
主要有两点注意点,var 声明的变量个 let 声明的变量以及 异步执行 的问题
var 声明的变量存在变量提升,而 let 声明的变量有只在当前作用域生效的特点
for (var i = 0; i < 4; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
//这里很多人认为会输出:0,1,2, 3,实际输出 4 个 4
//原因是 setTimeout 是个异步执行程序,他会等同步任务执行完之后,再从任务队列中拿出来运行
//而此时的 i 已经在最后一次 for 循环结束后变成了 4
//稍微更改一下,把 var 变成 let
for (let i = 0; i < 4; i++) {
setTimeout(function() {
console.log(i);
}, 300);
}
//输出 0 1 2 3
//原因是 let 声明的变量有只在当前作用域生效的特点,也就是说每次 for 循环都会创建一个独立的作用域,此时 let 声明的变量只能在当前作用域中被使用
for 循环 和 let 连起来使用可以避免很多麻烦, let 和 for 循环应用实例
//创建10个 a 标签 , 点击标签 显示对应标签的序号
for (let i = 0; i < 10; i++) {
var a = document.createElement("a"); //创建一个元素 a
document.body.appendChild(a); //将元素插入页面中
a.innerHTML = (i+1) + '
'; //a 标签 序号 + 换行
a.addEventListener('click',function(){ //添加点击事件
console.log(i+1);
})
}
var str1 = 'get-element-by-id'
var arr1 = []
var arr2 = str1.split('-') //把数组转化成字符串
//console.log(arr2)
for (let i in arr2) { // for...in 语句用于遍历数组或者对象的属性
var letter = arr2[i].replace(arr2[i][0], arr2[i][0].toUpperCase())
//arr2[i][0] 表示第 i 个元素的 第 0 个值
//string.replace( searchvalue , newvalue )
//searchvalue 要替换的字符 newvalue 替换后的字符
arr1.push(letter)
//将其添加到预先声明好的空数组里
}
var str2 = arr1.join('')
//join() 将数组转化成字符串
console.log(str2)
replace() 字符串替换
toUpperCase() 大写
replaceFirst() 替换遇到的第一个字符串