JavaScript对象函数基础01(对象作为引用类型,函数的创建和arguments,return,回调与递归)

一、對象

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

 

原文地址:https://www.cnblogs.com/ananasfleisch/p/13281540.html