1.對象的創建
var obj=new Object();//構造函數創建法 var obj={};//字面量創建法 var obj=Object.create({})
2.鍵值對
對象key只能是字符類型
var a="keys"; var obj={ //key:value name:"xietian", //"name":"xietian"//字符型key [a]:16,//變量型key 5:10 } console.log(obj.name); console.log(obj.keys); console.log(obj.5);//點語法拒絕使用非字符類型 console.log(obj[5]);//在對象中key除了字符類型以外只能支持symbol類型,這裏的5隱式轉換成了字符 var o={ a:1 } var o1={ b:2 } var obj={}; var arr=[1,2,3]; var arr1=[4,5,6]; obj[o]=10;//因爲對象的屬性名必須為字符類型,隱式轉換,所以不管什麽對象都爲[object Object] 10 obj[undefined]=20;//undefined:20 obj[null]=30;//null:30 obj[arr]=40;//1,2,3:40 console.log(obj[arr1]);//undefined 爲什麽以後學 console.log(obj[o1]);//對象轉換成字符串了[object Object],結果為10 console.log(String(o));//[object Object] console.log(obj); //key如果不是字符串,不能使用.語法
3.對象引用
//對象引用存儲 //對象存儲在堆中 //對象打印時遇到的數據問題 var obj={ a:1 } console.log(obj);//直接打印是點開以後是{a:10} obj.a=10; //a的值不會改變 //JSON將對象轉換成字符串 console.log(String(obj));//[object Object] var str=JSON.stringify(obj); //JSON格式字符串 //'{"a":1,"b":2,"c":"xietian","checked":true}' console.log(str);//{a:1} obj.a=10; //將JSON格式字符串轉換為對象 var o=JSON.parse(str); console.log(o); //{a:1} //對象的引用關係 var obj={ a:1 } var obj1=obj; obj.a=100; console.log(obj1.a);//100 //obj和obj1的值都是一樣的引用地址,所以改變一個對象的内容時,同時改變 var o={a:1}; var o1=o; o1.n=o={b:3}; //求o1和o的值 //分兩步,先把值賦給最左邊的o1.n,在把值賦給o //o1.n為{a:1},由第二句var o1=o; o1為{a:1,n:{a:1}} //o為o{b:3} var o={a:1}; var o1={a:1}; console.log(o===o1);//判斷對象是否相等,僅判斷地址,而不是判斷對象内容false console.log(JSON.stringify(o)===JSON.stringify(o1));//有漏洞,有可能出錯true
4.垃圾回收機制
obj=null;在堆中對應的内容的引用列表被刪除,儅別的東西占用内存達到峰值時,垃圾回收機制
// 垃圾回收机制 在堆中的对象可能被若干个变量引用其地址,如果这个对象在后面的内容中不再使用,我们需要将堆中的这个对象清除,否则,不会被浏览器自动清除,这样就会造成垃圾产生,当不断产生这种垃圾时,我们就把这种情况叫内存泄漏
// 如何处理内存泄漏 先创建每个对象的管理池,针对每个对象所引用它的变量做统一存储管理,如果 需要清理该对象时,将引用它的所有变量设置为null,当内存上限达到峰值时,系统 会通过垃圾回收车将这些堆中无引用的对象全部清除回收,这就是垃圾回收机制
5.對象的遍歷和複製
//遍歷對象(使用for in) var obj={ c:3, d:4, e:5, f:{ a:1, b:2, c:3 } } for(var prop in obj){ console.log(prop,obj[prop]) } console.log(obj); //沒有先後順序,對象遍歷通過添加屬性的先後順序遍歷的 var obj1={}; for(var prop in obj){ console.log(prop); obj1[prop]=obj[prop]; } obj.a=10; console.log(obj1);//沒有引用關係,對象複製c d e f然後打印原obj一樣的對象,obj後來增加的屬性值對obj1沒有影響 //對象的深複製 var obj1=JSON.parse(JSON.stringify(obj));//不能複製對象的方法,只是複製對象裏的值,沒有引用關係,obj後來增加的屬性值對obj1沒有影響 obj.f.a=100; console.log(obj,obj1); //不可枚舉屬性__proto__,對象的方法 var obj={ a:1, b:true, c:function(){ } } // JSON方法不可以将对象中方法进行转换 var str=JSON.stringify(obj); console.log(str); var obj={ a:{ a:1 }, b:{ c:2 } } var o=obj.a;//把obj.a的地址賦給o var o1=obj.b; o.a=10;//改變地址内的屬性值 o={c:1};//改變地址,覆蓋了之前的obj.a的那個對象 console.log(obj,o);//{a:{a:10},b:{c:2}};{c:1} // 删除属性 var obj={ a:1, b:2 } delete obj.a; console.log(obj);
二、函數
1.函數的創建
//函數是一個對象,存儲在堆中 1.function fn1(arg1,arg2){//函數的聲明 //函數語句塊 console.log("a"); } fn1();//函數的執行 //函數是一個對象,這種普通函數的創建,在script被執行時就被放入堆中,并且在棧中以函數名作爲變量引用到堆中這個函數地址 //函數可以創建在當前script的任意位置,都可以調用,在這個script之前的script引入不了 //函數在創建時就創建這個函數名的變量,因爲是全局的,所以就會被污染覆蓋 //覆蓋前仍然可以執行當前函數,覆蓋后,函數不能夠執行了 fn1(); //如果函數中沒有使用return關鍵詞,函數返回一個undefined值 console.log(fn1());//a undefined console.log(fn1);//返回這個函數 ƒ fn1(arg1,arg2){ //函數語句塊 console.log("a"); } console.dir(fn1);//将这种对象以对象形式展现 f fn1(arg1,arg2)裏面是這個函數的對象形式的結構 fn1.a=10;//fn和fn1添加了一個對象的屬性a:10 var fn=fn1;//函数是a:10对象,因此局部引用关系 fn();//a 2.匿名函數創建方式 fn2();//這裏調用會報錯 var fn2=function(){ //匿名函數創建,創建好的匿名函數賦值給fn2這個變量 //變量什麽時候定義,這個變量才能在棧中產生,才可以被調用 console.log("aaa"); } fn2();//aaa //在对象中,可以设置一个属性是一个函数,这样就给了对象定义了一个方法 var bn=document.getElementById("bn"); bn.onclick=function(){ console.log("aa"); bn.onclick=null;//執行一次就把這個函數刪除 } (function(){ console.log("aa"); //會自動執行,以後永遠不能再調用 })(); 3.構造函數創建函數 // 构造函数创建,每个参数都必须是字符串 // 除了最后一个参数是函数的语句块以外,前面所有的参数都是该函数的参数 var fn=new Function("a","b","console.log(a+b)"); function fn(a,b){ console.log(a+b); } fn(3,4); //第三种方式我们不推荐,因为这种语法会导致解析两次代码(第一次解析常规JS代码,第二次是解析传入构造函数中的字符串),从而影响性能,但我们可以通过这种语法来理解函数是对象,函数名是指针的概念。 //函數的刪除 bn.onclick=null;//匿名函數刪除 delete obj.function//對象下的方法刪除
2.函數的參數
在函数后面括号中填写的变量叫做参数,为什么要填写参数?函数如果没有参数,参数目的是解决函数在不同清空下解决不同问题
// 在设计函数时,尽量不要让函数内部与外部有关联 // 尽量让函数内部是一个独立的个体 // 抽象function fn(a, b) {} function createTable(row, col) { var str = "<table>"; for (var i = 0; i < row; i++) { str += "<tr>"; for (var j = 0; j < col; j++) { str += "<td></td>"; } str += "</tr>"; } str += "</table>"; document.body.innerHTML += str; } createTable(3, 10);//3行10列的列表 createTable(5, 10); createTable(6, 8); function fn1(a,b){ var s=a+b; console.log(s); } function fn2(a,b){ var s=a-b; console.log(s); } function fn3(a,b){ var s=a*b; console.log(s); } function fn4(a,b){ var s=a/b; console.log(s); } function fns(a,b,type){ var s; switch(type){ case "+": s=a+b; break; case "-": s=a-b; break; case "*": s=a*b; break; case "/": s=a/b; break; } console.log(s); } fns(3,5,"*"); fn1(3,5); fn3(3,5); //在js中,因为js是一种弱类型语言,因此不能对参数约束其类型 // 这就会造成,因为使用函数者输入的参数不符合需求而造成代码出错,无法通过白盒测试 function fn4(a,b){ if(isNaN(a) || isNaN(b)) return "输入参数错误"; if(b===0) return "除数不能为0"; var s=a/b; return s; } var s=fn4(3,5); console.log(s); // ES5版本中 js中参数不能设置初始值,不填写参数就是undefined // 这个函数定义时的参数叫做形参 function fn5(a,b,c,d){ console.log(a,b,c,d); } // 这里执行时填入的参数叫做实参,实参是按照形参顺序一一赋值给形参 // 如果实参数量小于形参数量,后面的形参值就是undefined // fn5(1,2,4);
3.arguments的使用
// 定义函数时没有定义参数 // 如果实参数量大于形参数,使用arguments // arguments只能出现在函数语句块中 // 用于当前函数的参数不固定数量 function fn1(){ console.log(arguments); console.log(arguments[0],arguments[1]) } // 当执行函数时传入实参 // fn1(3,4,5,6); function sum(){ var s=0; for(var i=0;i<arguments.length;i++){ s+=arguments[i]; } console.log(s); } sum(3,4);//7 sum(3,4,5);//12 sum(3,4,5,6); //18 function max(){ if(arguments.length===0) return "没有值"; // if(arguments.length===1) return arguments[0]; var s=arguments[0]; for(var i=1;i<arguments.length;i++){ s=s>arguments[i] ? s : arguments[i]; } return s; } var x=max(1,4,7);//7 var x= max(3);//3 console.log(x); function fn1(){ //console.log(arguments.callee);//当前函数 //console.log(arguments.callee.name);//当前函数的名字fn1 console.log(arguments.callee.caller);//调用当前函数的外部函数 } function fn2(){ fn1(); } function fn3(){ fn1(); } fn2();//ƒ fn2(){ fn1(); } fn3(); //ƒ fn3(){ fn1(); } var i=0; (function(){ i++; console.log(i); if(i<5) arguments.callee();//執行當前匿名立即執行函數,打印結果1 2 3 4 5 })();
4.變量作用域
// 变量只能在局部中使用,因此叫做局部变量 // 在任何地方都可以使用的变量叫做全局变量 var a=10; function fn(){ // 被定义在函数内部的变量,使用范围仅在函数内部 // 并且当前函数执行完成以后,这个变量会被销毁 // 下一次这个函数再执行时,会重新定义这个变量 // 并且变量不能被保存在函数执行完成后还能使用 var a=1; console.log(a);//优先局部变量 // console.log(a+window.a)//ES6被禁止 } fn(); //1 console.log(a);//10 var a=10; function fn(){ // 如果当前函数内没有定义与全局变量相同的局部变量名 // 这里直接调用全局变量 console.log(a); } fn();//10 var a=10; function fn(){ var a; console.log(a);//遵照局部变量优先原则 } fn(); //undefined var a=10; function fn(){ //打印变量早于定义该局部变量之前,打印undefined console.log(a);//任然遵照局部变量优先原则 var a=4; } fn(); //undefined // 在函数中只要看到使用var定义的变量,这个变量就一定是局部变量,而且这个变量被优先 var a=10; function fn(){ console.log(a);//这里没有使用var,当前a是全局的 a=4; } fn(); //10 var a=10; function fn(a){ // 当在函数中设置了参数, // 那么就相当于,这个参数就是被var定义好的局部变量 console.log(a); } fn(5);//5 console.log(a); //10 var a=100; function fn(a){ console.log(a);//6 var a;//因为参数本身就是局部变量,所以重新定义不赋值不起作用,參數優先于局部變量 console.log(a);//6 a=10; console.log(a);//10 } fn(6); var a; function a(a){ console.log(a);//6 var a; console.log(a);//6 a=10; console.log(a);//10 } a(6);//可以执行 a=100;//改變了函數a,所以下一步報錯 a(6);//报错 var a; function a(a,a){ console.log(a);//7 var a; console.log(a);//7 a=10; console.log(a);//10 } a(6,7);//可以执行 a=100; a(6,7);//报错 var a={ a:function(a){ var a; console.log(a); } } a.a(5); //5 function fn(f){ var x=20; f(x);//x=20作爲實參傳給了fn1(x),此處x是實參 } function fn1(x){//此處x是形參 console.log(x); } fn(fn1); //20 var name = 'World!'; (function () { if (typeof name === 'undefined') { var name = 'Jack'//因爲在函數内部,不關if else的事 console.log(name) } else { console.log(name) } })()//Jack
5.return
function fn(a,b){ // if(arguments.callee.length<arguments.length) console.log(arguments.length);//实参的长度,也就是实际传入的参数长度 } fn(1,2,3,4); console.log(fn.length);//形参长度,就是函数定义参数数量 fn=null; 清除函数 function fn(){ } delete window.fn;//无效 // 函数在执行时,将返回函数中return 内容 // 如果return 后没有内容或者没有return ,返回一个undefined function fn(){ return 1;1 } function fn1(){ return 2; } var s=fn();// console.log(s); var s=fn()+3;//4 var s=fn()+fn1();//3 函数返回的作用 1、返回局部变量 function fn(){ var a=1; a+=3; return a; } function fn(_name,_sex){//返回對象 var obj={ name:_name, sex:_sex, } return obj; } function fn(_name,_sex){ return { name:_name, sex:_sex, } } var obj=fn("xietian","男"); var obj1=fn("zhangsan","男"); console.log(obj,obj1); function fn(){ var fn1=function(){ console.log("aa"); } return fn1;//返回函數 } function fn(){ return function(){ console.log("aa"); } } var f=fn(); f();//aa 2、返回参数 function fn(a,b){ a+=b; return a; } var a=10; var b=20; fn(a,b); console.log(a); //10 function fn(obj){ obj.a=10; return obj; } var obj={ a:1 } var obj1=fn(obj);//obj變成了{a:10} console.log(obj===obj1); //true 3、跳出,切断,不继续执行 function fn(a,b){ if(isNaN(a) || isNaN(b)) return; console.log("是数值"); } fn(3,5); //是數值 var sum=fn(3,5,"*"); console.log(sum);//是數值 undefined function fn(a,b,type){ if(isNaN(a) || isNaN(b)) return "错误的数字"; switch(type){ case "+":return fn1(a,b); case "-":return fn2(a,b); case "*":return fn3(a,b); case "/":return fn4(a,b); default: return "错误的符号"; } } function fn1(a,b){ return a+b; } function fn2(a,b){ if(a<0) a=0; return a-b; } function fn3(a,b){ return a*b; } function fn4(a,b){ if(b===0) return "错误除数"; return a/b; } function fn1(a,b){ var s=a+b; console.log(s); } function fn2(a,b){ var s=a-b; console.log(s); } function fn3(a,b){ var s=a*b; console.log(s); } function fn4(a,b){ var s=a/b; console.log(s); } function fns(a,b,type){ var s; switch(type){ case "+": s=a+b; break; case "-": s=a-b; break; case "*": s=a*b; break; case "/": s=a/b; break; } console.log(s); } var str="零一二三四五六七八九十"; console.log(str[5]); var s=30;//"三十"; var s=29;//"二十九"; var s=16;//"十六"; //切断跳出 function changeCN(num){ if(isNaN(num)) return "这不是一个数字"; if(num>=100 || num<0) return "不是范围内的数字"; num=parseInt(num); if(num<11) return str[num]; if(num<20) return "十"+str[num%10]; if(num%10===0) return str[num/10]+"十"; return str[parseInt(num/10)]+"十"+str[num%10]; } console.log(changeCN(96)); //九十六 function fn1(){ console.log("a"); fn2(); console.log("c"); } function fn2(){ console.log("b"); fn3(); console.log("d"); } function fn3(){ return console.log("e"); } fn1(); // a b e d c function fn1(a){ if(a===1) return fn2(); if(a===2) return fn3(); if(a===3) return fn4(); if(a===4) return fn5(); var s=0; switch(a){ case 1: s+=fn2(); case 2: s+=fn3(); case 3: s+=fn4(); case 4: s+=fn5(); } return s; } function fn2(){ console.log(1) return 10; } function fn3(){ console.log(2) return 20; } function fn4(){ console.log(3) return 30; } function fn5(){ console.log(4) return 40; } var s=fn1(3); console.log(s); //3 30 //函数执行中执行其他函数,另一个函数中的内容执行完成后才会继续执行当前函数 // 当需要并列执行多个时,我们可以在一个函数中统一调配执行的顺序
三、回調
function fn1(fn){ fn(); } function fn2(){ console.log("aaa"); } fn1(fn2); //aaa // 将一个函数以参数的形式传入到另一个函数中,并且在那个函数执行 var i=0; fn1();//3 3 3 function fn1(){ i++; if(i<3) fn2(); console.log(i); } // 函数内执行当前自身函数 function fn2(){ i++; if(i<3) fn3(); console.log(i); } function fn3(){ i++; if(i<3) fn4(); console.log(i); } // 不被执行 function fn4(){ i++; if(i<3) fn1(); console.log(i); } //根据内存大小设置递归上限的次数,如果递归次数太多,就会堆栈上限溢出 //Uncaught RangeError: Maximum call stack size exceeded var i=0; fn1(); function fn1(){ i++; if(i<20000) fn1(); // console.log(i); } // 回调: // 1、回调一般用于当处理某件事情需要等待时,设置回调 // 2、当不需要关心具体后续需要处理的事情时,设置回调 // setTimeout(超时执行的函数,超时时间,执行函数的参数) 返回一个id数 console.log("a"); var id=setTimeout(fn,2000,5);//异步,一定时间后处理问题 function fn(n){ console.log(n); clearTimeout(id);//清除这个超时函数 } console.log("b"); //a b 2s之後打印5 var id=setInterval(fn,2000); var num=0; function fn(){ num++; console.log("aa"); if(num>3) clearInterval(id); } function fns(a,b,fn){ if(isNaN(a) || isNaN(b)) return "错误的数据"; return fn(a,b); } function fn1(a,b){ return a+b; } function fn2(a,b){ if(a<0) a=0; return a-b; } function fn3(a,b){ return a*b; } function fn4(a,b){ if(b===0) return "错误除数"; return a/b; } var s=fns(3,5,fn3); console.log(s); //15 // 红绿灯 var id; function setLight() { arguments[0](arguments[1], arguments[2]); } function redLight(fn, fn2) { clearTimeout(id); console.log("红灯"); id = setTimeout(fn, 2000, fn2, arguments.callee); } function yellowLight(fn, fn2) { clearTimeout(id); console.log("黄灯"); id = setTimeout(fn, 2000, fn2, arguments.callee); } function greenLight(fn, fn2) { clearTimeout(id); console.log("绿灯"); id = setTimeout(fn, 2000, fn2, arguments.callee); } setLight(yellowLight, redLight, greenLight); //回调函数完成循环局部传参返回值 function fn1(fn, i, sum) { if (i === undefined) (i = 1), (sum = 1); i++; if (i > 100) { return sum; } return fn(arguments.callee, i, sum); } function fn2(fn, i, sum) { sum += i; return fn(arguments.callee, i, sum); } function fn3(fn, i, sum) { sum *= i; return fn(arguments.callee, i, sum); } var sum = fn1(fn3); console.log(sum);//9.33262154439441e+157
<div> <div id="div0"> <span id="span0"></span> <span></span> <span id="span1"></span> <ul> <li id="li0"></li> <li></li> <li id="li1"></li> <li id="li2"></li> <li id="li3"></li> </ul> </div> <div id="div1"> <ul> <li></li> <li id="li4"></li> <li> <a href="#" id="a0"></a> </li> <li id="li5"><a href="#"></a></li> <li><a href="#" id="a1"></a></li> <li id="li6"></li> </ul> </div> <p id="p0"></p> <p id="p1"> <div id="div2"></div> <div></div> <div><a href="#"></a></div> <div id="div3"></div> </p> <p id="p2"></p> <p id="p3"> <span></span> <span id="span2"></span> <span><a href="#"></a></span> <span id="span3"></span> <span id="span4"></span> </p> </div> <script> console.log(document.body.children) function getDOMObj(parent,obj){ obj=obj || {}; parent=parent || document.body; if(parent.id) obj[parent.id]=parent; for(var i=0;i<parent.children.length;i++){ getDOMObj(parent.children[i],obj); } return obj; } var obj=getDOMObj(); console.log(obj); var obj={ a:1, b:2, c:{ a:1, b:2, c:{ a:1, b:2, c:{ a:1, b:2, c:3 } } }, d:{ a:{ a:1, b:{ a:1 }, c:{ b:2 } }, b:{ a:1, b:{ c:3 }, c:{ d:4 } }, c:{ a:1, b:{ e:function(){ console.log("a"); } }, c:{ } } } } var obj1=obj;//赋值obj里面的属性发生改变,obj1里面的也会改变 var obj1={} for(var prop in obj){ obj1[prop]=obj[prop]; } obj.a=10; obj.c.a=10; console.log(obj1); function cloneObj(obj,target){ target=target || {}; for(var prop in obj){ if(typeof obj[prop]==="object" && obj[prop]!==null){ target[prop]={}; cloneObj(obj[prop],target[prop]) }else{ target[prop]=obj[prop]; } } return target; } var obj1=cloneObj(obj); obj.c.a=10; obj.d.b.b.c=100; console.log(obj1);