day0322
递归
递归的执行
函数在没有完全执行结束时,内部的所有变量都不会被销毁
递归会建立一个函数的副本,在堆中建立相同的函数引用,递归时调用这个函数引用
var i=0;
function fn1(){
var a=3;
i++;
if(i<3) fn2();
console.log(i);//最后打印的
}
function fn2(){
var a=3;
i++;
if(i<3) fn3();
console.log(i);//第二个被打印的
}
function fn3(){
var a=3;
i++;
console.log(i);//最先打印的
}
fn1();
用递归遍历链表
var obj={value:1,next:{value:2,next:{value:3,next:{value:4,next:{value:5,next:null}}}}};
function fn1(obj){
console.log(obj.value);
if(obj.next) fn1(obj.next);
}
fn1(obj);
遍历对象
//创建对象
var obj = {
a1: 1,
b1: 2,
c1: 3,
d1: {
a2: 4,
b2: 5,
c2: 6,
e2: {
a4: 7,
b4: 8,
c4: 9,
d5: {},
},
d2: {
a3: 10,
b3: 11,
c3: 12,
f3: {
a4: 13,
b4: 14,
c4: 15,
d5: {},
},
d3: {
a4: 16,
b4: 17,
c4: 18,
d5: {},
},
},
},
};
深查找
递归查找对象中属性值符合要求的属性
function fn3(o,value){
for(var prop in o){
if(o[prop]===value) return prop;
if(typeof o[prop]==="object" && o[prop]!==null){
var s=fn3(o[prop],value)
if(s) return s;
}
}
}
var prop=fn3(obj,14);
console.log(prop);
广度遍历 深度遍历
对象的广度遍历使用for in
对象的深度遍历使用递归
function fn1(obj){
for(var prop in obj){
console.log(prop,obj[prop]);
if(typeof obj[prop]==="object" && obj[prop]!==null)
fn1(obj[prop])
}
}
fn1(obj);
对象深复制 简单版
function fn1(source,target){
if(target===undefined) target={};
for(var prop in source){
if(typeof source[prop]==="object" && source[prop]!==null){
target[prop]={};
fn1(source[prop],target[prop])
}
else {
target[prop]=source[prop];
}
}
return target;
}
var o=fn1(obj);
console.log(obj)
console.log(o);
console.log(obj==o);
二叉树遍历
js没有二叉树,所以要自己重构
//创建二叉树
var obj={
value:0,
left:{
value:1,
left:{
value:3,
},
right:{
value:4,
}
},
right:{
value:2,
left:{
value:5,
},
right:{
value:6,
}
}
}
先序遍历
根左右
function fn1(o){//先序遍历 根左右
console.log(o.value);
if(o.left) fn1(o.left);
if(o.right) fn1(o.right);
}
fn1(obj);
中序遍历
左根右
function fn2(o){//中序遍历 左根右
if(o.left) fn2(o.left);
console.log(o.value);
if(o.right) fn2(o.right);
}
fn2(obj);
后序遍历
左右根
function fn3(o){//后序遍历 左右根
if(o.left) fn3(o.left);
if(o.right) fn3(o.right);
console.log(o.value);
}
fn3(obj);
return在递归中的变化
十进制转二进制
function fn1(n, str) {
if (str === undefined) str = "";
str = (n % 2) + str;
n = parseInt(n / 2); //7
if (n) return fn1(n, str);
return str;
}
console.log(fn1(26));
十进制转十六进制
function fn1(n,str){
if(str===undefined) str="";
n%16>9?str=String.fromCharCode(87+n%16)+str:str=n%16+str;
n=parseInt(n/16);
if(n) return fn1(n,str);
return str;
}
console.log(fn1(26));
递归实现反向排序
//得到新的字符串,原字符串不变
function text_reverse(str,str_length,new_str){
if(str_length===undefined) str_length=str.length;
if(new_str===undefined) new_str="";
return str_length==0?new_str:text_reverse(str,--str_length,(new_str+=str[str_length]))
}
字符串的length为只读属性
var str="abcde";
console.log(str.length);//字符串的length为只读属性
str.length--;//无效果
console.log(str.length);
console.log(str[str.length-1]);//通过下标访问字符串元素
var new_str=text_reverse(str);
console.log(str);
console.log(new_str);
body标签下子元素
document.body
document.body.children.length
数组
数组是一个列表,有序列表
引用类型对象
js中数组的元素可以类型不同,但建议保持类型相同
起始0
var arr=[3,4,5,10];
console.log(arr[0]);
数组实际上是按照下标存储元素的方式,将值存在列表中
下标 arr[1] 元素存储的位置 1就是下标
元素 arr[1]—>4 arr[1]下标变量 4就是元素
数组的创建
1.字面量创建
var arr=[1,2,3];
因为空元素就是下标没有对应的值,所以可以通过 下标 in 数组 这种方式判断
空元素与undefined的区别:
var arr=[1,,3,undefined,5];//中间有个空元素
for(var i=0;i<5;i++){
if(!(i in arr))continue;
console.log(arr[i]);
}
2.构造函数创建
var arr=new Array(1,2,3,4);
var arr=Array(1,2,3,4);
两种方法相同,之后讲怎么相同
如果构造函数中的元素数量大于1个,则所有的元素都是这个数组的元素
构造函数中的参数只有一个时,这个一个就是数组的长度
var arr=new Array(5);//相当于arr=[,,,,]
console.log(arr);
如果仅有一个参数,并且这个参数时数值类型,但是并不是正整数,就会报错
var arr=new Array(3.4);
var arr=new Array(-4);
如果仅有一个参数,但是这个参数不是数值类型,则会将这个参数放在数组的第0位
var arr=new Array("a");
console.log(arr);
3.对象创建
var arr=new Object([1,2,3,4]);
console.log(arr);
没什么用
数组长度
数组有length属性:有值或者空元素的数量
字符串有length属性,只读
对象无length属性
var arr=[11,21,31,41,51];
console.log(arr.length);
console.log(arr[arr.length-1]);
arr[30]=10;
console.log(arr);
console.log(arr.length);
var arr=[4,5,8,2,1];
for(var i=0;i<11;i++){
// arr[i]=i;//如果这样写会覆盖原来的元素
arr[arr.length]=i;
}
console.log(arr);
arr.length是一个可读可写的属性
如果当前数组的长度小于设置的长度,则增加(新长度-原长度)数量的元素
var arr=[];
arr.length=5;//如果当前数组的长度小于设置的长度,则增加(新长度-原长度)数量的元素
console.log(arr);
如果新长度小于原长度,就会从后面删除(原长度-新长度)数量的元素
var arr=[1,2,4,5];
arr.length=2;//如果新长度小于原长度,就会从后面删除(原长度-新长度)数量的元素
console.log(arr);
清空数组
最好的方法:arr.length=0;
var arr=[1,2,4,5];
arr.length=0;//清空数组 最好的方法
console.log(arr);
用length删除尾部的最后一个元素
arr.length–;
var arr=[1,2,4,5];
arr.length--;//删除尾部的最后一个元素
console.log(arr);
length需要是正整数(0是清空数组)
var arr=[1,2,4,5];
arr.length-=5;//报错,length不能小于0或者是负数
console.log(arr);
var arr=[1,2,4,5];
arr.length="a";//报错,必须是一个正整数
console.log(arr);
复制数组
var arr=[1,2,3,4];
var arr1=arr;//这样复制的是引用地址
arr[2]=10;
console.log(arr1);
var arr=[1,2,3,4];
var arr1=[];
//for in 遍历复制值
for(var i=0;i<arr.length;i++){
arr1[i]=arr[i];
}
arr[0]=10;
console.log(arr1);
数组中可存储:
var arr=["a","b","c"];
var arr=[true,false];
var arr=[{a:1,b:2},{c:3,d:4}];//对象型数组
var arr=[[1,2,3],[4,5,6]];//二维数组
var arr=[function(){
console.log("aaa");
},function(){
console.log("bbb");
}]
// 函数数组
数组的对象方法:
针对一个实例
push
尾部添加一个或者多个元素,并且返回数组的新长度
var arr=[];
var i=0;
while(arr.push(i++)<10);
console.log(arr);
var arr=[];
var len=arr.push(1);//len为此时数组的新长度
console.log(len);
arr.push(1,2,3);
console.log(arr);
重构:
function array_push(arr:Array){
//:Array表示arr的数据类型为了显示代码提示,运行之前需要删掉
if(arr==undefined || arr.constructor!==Array) throw new Error("错误参数");
//throw new Error() 抛出错误 中断后续代码的执行
if(arguments.length===1) return arr.length;
for(var i=1;i<arguments.length;i++){
arr[arr.length]=arguments[i];
}
// 给数组尾部一旦添加元素,arr.length就会自动重设
return arr.length;
}
var arr=[];
var len=array_push(arr,3,4,6,2,1);
console.log(len,arr);
pop
删除数组尾部的一个元素,并且返回被删除的元素
var arr=[4,3,2,1];
var item=arr.pop();
console.log(item,arr);
重构:
function array_pop(arr){
var item=arr[arr.length-1];
arr.length--
return item;
}
var arr=[4,3,2,1];
var item=array_pop(arr);
console.log(arr,item);
shift
删除数组头部的一个元素,并且返回被删除的元素
var arr = [1, 2, 3, 4];
var item=arr.shift();
console.log(item,arr);
重构:
function array_shift(arr){
if(arr.length===0) return;
var item=arr[0];
for(var i=0;i<arr.length-1;i++){
arr[i]=arr[i+1];
}
arr.length--;
return item;
var arr = [1, 2, 3, 4];
var item=array_shift(arr);
console.log(item,arr);
unshift
英文:数组头部插入,首插入
向数组的头部添加一个元素或者多个元素,并且返回数组的新长度
var arr=[1,2,3];
var len=arr.unshift(0);
console.log(len,arr);
重构:
function array_unshift(arr) {
if (arr == undefined || arr.constructor !== Array)
throw new Error("错误参数");
if (arguments.length === 1) return arr.length;
var len = arguments.length - 1; //当前添加参数数量
arr.length = len = len + arr.length; //添加元素后数组的新长度
while (len > 0) {
if (len > arguments.length - 1) {
arr[len - 1] = arr[len - arguments.length];
} else {
arr[len - 1] = arguments[len];
}
len--;
}
return arr.length;
}
var arr = [1, 2, 3, 4];
array_unshift(arr, 0,1,23,5);
console.log(arr);
concat
英文:合并数组,函数,合并多个字符串
合并数组,可以将一个数组和另外一个数组合并成一个数组,合并成的是新数组,原数组不变
可以用一个数组合并多个元素,产生一个新数组
如果不填写参数,则复制原数组,产生一个新数组
var arr=[1,2,3,4];
var arr1=arr.concat([5,6]);
console.log(arr1);
用concat复制数组
var arr=[1,2,3,4];
var arr1=arr.concat();
arr[0]=10;
console.log(arr);
console.log(arr1);
var arr=[1,2,3,4];
var arr1=arr.concat(4,5,[1,2,3],6)
console.log(arr1);
重构:
function array_concat(arr){
if(arr==undefined || arr.constructor!==Array) throw new Error("不是一个数组");
var arr1=[];
for(var i=0;i<arr.length;i++){
arr1[i]=arr[i];
}
if(arguments.length===1) return arr1;
for(var j=1;j<arguments.length;j++){
if(arguments[j] && arguments[j].constructor===Array){
for(var k=0;k<arguments[j].length;k++){
arr1[arr1.length]=arguments[j][k];
}
}else
arr1[arr1.length]=arguments[j];
}
return arr1;
}
var arr=[1,2,3,4];
var arr1=array_concat(arr);
arr[0]=100;
console.log(arr);
console.log(arr1);
join
英文:连接,结合
连接字符串,用符号连接数组的元素并且生成字符串
var arr=[1,2,3,4];
var str=arr.join();
var str=arr.join("#");//除了undefined,都隐式转换为字符串
console.log(str);
重构:
function array_join(arr,separator){
if(arr==undefined || arr.constructor!==Array) throw new Error("不是一个数组");
if(separator===undefined) separator=",";
separator=String(separator);
var str="";
for(var i=0;i<arr.length-1;i++){
str+=arr[i]+separator;
}
str+=arr[arr.length-1];
return str;
}
var arr=[1,2,3,4];
var str=array_join(arr,"");
console.log(str);
fill
英文:(使)充满,填满
fill() 方法用于将一个固定值替换数组的元素
var arr=[];
arr.length=10;
arr.fill(1);
console.log(arr);
相当于
var arr=Array(10).fill(1);
console.log(arr);
起2止5
var arr=Array(10).fill(1,2,5);//起2止5
console.log(arr);
重构:
function array_fill(arr,item,start,end){
if(arr==undefined || arr.constructor!==Array) throw new Error("不是一个数组");
if(start===undefined) start=0;
if(end===undefined) end=arr.length;
for(var i=start;i<end;i++){
arr[i]=item;
}
return arr;
}
var arr=Array(10);
arr=array_fill(arr,1,2,5);
console.log(arr);
随机颜色
var color="#"+Array(6).fill(1).map(item=>parseInt(Math.random()*16).toString(16)).join("");
onsole.log(color);
每次刷新结果都不一样
静态方法:
针对类型
Array.from
将一个列表转换为数组
两个条件:
- 下标有0,1,2,3,4
- 必须要有length
function fn1(){
// var str= arguments.join("");//报错:arguments没有join方法
// console.log(str);
var arr=Array.from(arguments);
var str=arr.join("");
console.log(str);
}
fn1(1,2,3,4);
有下标有length属性的对象也可用Array.from转换为数组
var o={0:0,"1":1,"2":2,length:3};
console.log(Array.from(o));
重构:
Array.from_1=function(list){
var arr=[]
if(!list.length) return arr;
for(var i=0;i<list.length;i++){
arr[i]=list[i];
}
return arr;
}
简便写法 强记 之后再讲
return Array.prototype.slice.apply(list);
return Array.prototype.slice.call(list);
return [].slice.apply(list);
return [].slice.call(list);
return [].concat.apply([],list);
return Array.prototype.concat.apply([],list);
var o={0:0,"1":1,"2":2,length:3};
console.log(Array.from_1(o));
function fn1() {
var arr = Array.from_1(arguments);
var str = arr.join("");
console.log(str);
}
fn1(1,2,3,4);
Array.isArray
判断元素是否是数组
console.log( Array.isArray([1,2]));
console.log( Array.isArray({a:1,b:2}));
console.log( Array.isArray({0:0,1:1,2:2,length:3}));
重构:
Array.isArray_1=function(list){
return (list && list.constructor===Array) ? true :false
}
console.log(Array.isArray_1([1,2,3]))
console.log(Array.isArray_1({a:1,b:2}))
console.log(Array.isArray_1(null));