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);