目录:
1:call和apply方法调用
2:bind方法复制
3:函数中的几个属性值
4:高阶函数,函数作为参数
5:高阶函数,函数作为返回值。
6: 作用域链,作用域,预解析
7:闭包--延长作用域链
8: 沙箱:测试,虚拟环境
1:call和apply方法调用
<script> function f1 (x, y) { console.log("结果是:"+(x+ y) + this); } // 函数的调用 f1(10, 20); console.log("==========="); //1: 此时的f1实际上是当成对象来使用的,对象可以调用方法,apply和call方法也是函数的调用的方式 f1.apply(); f1.call(); //2: apply和call都可以让函数或者方法来调用,传入参数和函数自己调用的写法不一样,但是效果是一样的, apply传入的是数组, call,传入的是参数 f1.apply(null, [100, 200]); f1.call(null, 100, 200); console.log("==========="); function f2(x, y){ console.log("这个函数是window对象的一个方法"+ (x+y) + this); console.dir(this); } window.f2(10, 20); var obj = { age: 10, name: "张三", } //3: apply和call可以改变this的指向, window.f2.call(obj, 10, 20); window.f2.apply(obj, [10,20]); // 4:apply和call方法实际上并不在函数这个实例对象中,而是在Function的prototype,原型对象中。
原型对象可以看成+方法,实例方法可以当成-方法。调用+方法时候可以当成对象。 console.log(f2.__proto__ == Function.prototype); console.log(Function.prototype); //{ [native code] } console.dir(Function); script>
2:bind方法复制
<script> console.log("===== 11 =====") function f1 (x, y ){ console.log((x+y) + " :======>>>>"+this ); console.dir(this); } f1.bind(); // 方法复制了一份,并且传递参数,结果还是方法,方法没有调用。此时f1是对象。 // bind方法是复制的意思,可以在复制的时候传递参数,也可以在复制之后传递参数 // apply 和 call 是调用的时候改变this的指向 // bind是 复制的时候修改this的指向 var ff = f1.bind(null, 10, 20); console.log (ff); ff(); var f2 = f1.bind(null); f2(10, 20); console.log("===== 22 =====") // bind是方法复制,apply和call是方法调用 function Person (){ this.age = 10; } Person.prototype.eat = function () { console.log("这个是吃"); }; var per = new Person; var ff = f1.bind(per); ff(10, 20); console.log("===== 33 =====") function Person(age) { this.age = age; } Person.prototype.play = function () { console.log(this + "========>>>>" + this.age); } function Student (age) { this.age = age; } var per = new Person(10); var stu = new Student(20); var paly2 = per.play.bind(stu); paly2(); script>
3: 函数中几个属性
<script> //函数中有一个name属性----->函数的名字,name属性是只读的,不能修改 //函数中有一个arguments属性--->实参的个数 //函数中有一个length属性---->函数定义的时候形参的个数 //函数中有一个caller属性---->调用(f1函数在f2函数中调用的,所以,此时调用者就是f2) function f1(x,y) { console.log(f1.name); console.log(f1.arguments.length); console.log(f1.length); console.log(f1.caller);//调用者 } f1.name="f5"; f1(10,20,30,40); console.dir(f1); function f2() { console.log("f2函数的代码"); f1(1,2); } f2(); script>
4:高阶函数之参数是函数
<script> //fn是参数,最后作为函数使用了,函数是可以作为参数使用 function f1(fn) { console.log("f1的函数"); fn();//此时fn当成是一个函数来使用的 } //1: 传入匿名函数 f1(function () { console.log("我是匿名函数"); }); console.log("======= 22 ========"); // 命名函数 function f2() { console.log("f2的函数"); } // 2:传入的是命名函数 f1(f2); //函数作为参数的时候,如果是命名函数,那么只传入命名函数的名字,没有括号 script>
5: 函数作为返回值
<script> console.log("======== 11 ========="); function f1() { console.log("f1函数的开始"); return function () { console.log("我是函数,但是我是我是我为函数的返回值"); }; // 我是不会执行的,因为此行代码上面有return console.log("f1函数的结束"); } var f2 = f1(); f2(); console.log("======== 22 ========="); var num=10; console.log(typeof num);//获取num这个变量的数据类型 var obj={};//对象 //判断这个对象是不是某个类型的 console.log(obj instanceof Object); //获取某个对象的数据类型的样子 //Object.prototype.toString.call(对象);//此时得到的就是这个对象的类型的样子 //此时输出的是Object的数据类型 [object Object] console.log(Object.prototype.toString()); //输出的数组的数据类型 [object Array] console.log(Object.prototype.toString.call([])); var arr=[10,20,30]; console.log(Object.prototype.toString.call(arr)); console.log("======== 33 ========="); //获取某个对象的类型是不是你传入的类型 //[10,20,30] 是不是"[object Array]" //type---是变量----是参数----"[object Array]" //obj---是变量-----是参数----[10,20,30]; //判断这个对象和传入的类型是不是同一个类型 function getFunc(type) { return function (obj) { return Object.prototype.toString.call(obj) === type; } } var ff = getFunc("[object Array]"); var result = ff([10, 20, 30]); console.log(result); var ff1 = getFunc("[object Object]"); var dt = new Date(); var result1 = ff1(dt); console.log(result1); script>
6:作用域,作用域链,预解析
1:局部变量。函数中的变量是局部变量,外边无法访问。
2:预解析:变量的声明,和函数的声明提前
<script> // 变量---->局部变量和全局变量, // 作用域:就是变量的使用范围 // 局部作用域和全局作用域 // js中没有块级作用域---一对括号中定义的变量,这个变量可以在大括号外面使用 // 函数中定义的变量是局部变量 while(true){ var num=10; break; } console.log(num); { var num2=100; } console.log(num2); if(true){ var num3=1000; } console.log(num3); function f1() { //局部变量 var num1=10; } // console.log(num1); console.log("======== 22 ======"); // 作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了 // 层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错 var num=10; //作用域链 级别:0 var num2=20; var str = "abc" function f1() { var num2=20; function f2() { var num3=30; console.log(num); } f2(); } f1(); //预解析:就是在浏览器解析代码之前,把变量的声明和函数的声明提前(提升)到该作用域的最上面 //变量的提升 console.log(num); var num=100; //函数的声明被提前了 f1(); function f1() { console.log("这个函数,执行了"); } var f2; f2=function () { console.log("小杨好帅哦"); }; f2(); script>
7:闭包
1:闭包的定义:
函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者数据,此时就行程了闭包。
闭包缓存数据
总结:如果想要缓存数据,需要把数据放在外层函数和内层函数之间。
闭包的作用:缓存数据。优点也是缺点,没有及时释放
局部变量在函数中,函数使用结束后,局部变量就会被自动释放。
闭包后,里面的局部变量的使用作用域链就会被延长。
<script> /* 闭包 * 闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者数据,此时就行程了闭包。 *闭包的模式:函数闭包和对象闭包 * 闭包的作用:缓存数据,延长作用域链 * 闭包的优点和缺点:缓存数据 * 闭包的应用: * ****/ console.log("======= 11 ========"); // 1:函数式闭包 function f1() { var num = 10; // 函数 function f2() { console.log(num); } f2(); } f1(); console.log("======= 22 ========"); // 2:对象是闭包 function f3() { var num1 = 20; // 对象 var obj = { age : num1, } console.log(obj.age); } f3(); console.log("======= 33 ========"); function f4() { var num4 = 40; return function () { console.log(num4); return num4; }; } var ff1 = f4(); var result = ff1(); console.log(result); console.log("======= 44 ========"); function f5() { var num5 = 50; var obj = { age : num5, } return obj; } var resultObj = f5(); var result5 = resultObj.age; console.log(result5); script>
2:闭包的例子
<script> console.log("======= 11 ========="); function f1 () { var num = 10; num ++ ; console.log(num); } f1(); // 11 f1(); // 11 f1(); // 11 console.log("======= 22 ========="); // 闭包缓存数据 // 总结:如果想要缓存数据,需要把数据放在外层函数和内层函数之间。 // 闭包的作用:缓存数据。优点也是缺点,没有及时释放 // 局部变量在函数中,函数使用结束后,局部变量就会被自动释放。 // 闭包后,里面的局部变量的使用作用域链就会被延长。 function f2() { var num = 20; return function () { num ++; return num; }; } var ff1 = f2(); console.log(ff1()); // 21 console.log(ff1()); // 22 console.log(ff1()); // 23 console.log("======= 33 ========="); // 产生3次相同的随机数 // function f3() { var num3 = parseInt(Math.random()*10+1); return function () { console.log(num3); } } var ff3 = f3(); ff3(); ff3(); ff3(); script>
8:沙箱:虚拟测试和真实世界结果一样,不影响真实世界。
1:沙箱的定义和2中格式
<script> //沙箱:环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世界 // 沙箱 函数的自调用 console.log("======== 11 ========"); // 沙箱的模板,函数自调用两种格式 // 格式一: ()(); (function () { var num = 10; console.log(num + 10); })(); // 格式二:使用的比较多. (()); (function () { var num = 10; console.log(num + 20); }()); script>
9:递归
1:定义:自己调用自己一定 要有结束条件。
<script> console.log("======= 11 ======="); // 求n个数的和 // 倒序递归,结束条件 5+4+3+2+1 function getSum(n) { // 结束条件 if(n ==1){ return 1; } return n + getSum(n - 1); } console.log(getSum (5)); /* * * 执行过程: * 代码执行getSum(5)--->进入函数,此时的x是5,执行的是5+getSum(4),此时代码等待 * 此时5+getSum(4),代码先不进行计算,先执行getSum(4),进入函数,执行的是4+getSum(3),等待, 先执行的是getSum(3),进入函数,执行3+getSum(2),等待,先执行getSum(2),进入函数,执行 2+getSum(1);等待, 先执行getSum(1),执行的是x==1的判断,return 1,所以, * 此时getSum(1)的结果是1,开始向外走出去 * 2+getSum(1) 此时的结果是:2+1 * 执行: * getSum(2)---->2+1 * 3+getSum(2) 此时的结果是3+2+1 * 4+getSum(3) 此时的结果是4+3+2+1 * 5+getSum(4) 此时的结果是5+4+3+2+1 * * 结果:15 * * */ script>