js高级第四天(apply call bind以及闭包)

 2023-09-05 阅读 66 评论 0

摘要:apply和call方法的使用 作用:可以改变this指向 //apply和call都可以改变this的指向//函数的调用,改变this的指向// function f1(x,y) {// console.log((x+y)+":===>"+this);// return "这是函数的返回值";// }// //apply和

apply和call方法的使用

作用:可以改变this指向

 //apply和call都可以改变this的指向//函数的调用,改变this的指向//    function f1(x,y) {//      console.log((x+y)+":===>"+this);//      return "这是函数的返回值";//    }//    //apply和call调用//    var r1=f1.apply(null,[1,2]);//此时f1中的this是window//    console.log(r1);//    var r2=f1.call(null,1,2);//此时f1中的this是window//    console.log(r2);//    console.log("=============>");//    //改变this的指向//    var obj={//      sex:"男"//    };//    //本来f1函数是window对象的,但是传入obj之后,f1函数此时就是obj对象的//    var r3=f1.apply(obj,[1,2]);//此时f1中的this是obj//    console.log(r3);//    var r4=f1.call(obj,1,2);//此时f1中的this是obj//    console.log(r4);//方法改变this的指向//    function Person(age) {
//      this.age = age;
//    }
//    Person.prototype.sayHi = function (x, y) {
//      console.log((x + y) + ":====>" + this.age);//是实例对象
//    };
//
//    function Student(age) {
//      this.age = age;
//    }
//    var per = new Person(10);//实例对象
//    var stu = new Student(100);//实例对象
//    //sayHi方法是per实例对象的
//    per.sayHi.apply(stu, [10, 20]);
//    per.sayHi.call(stu, 10, 20);//apply和call的使用方法/** apply的使用语法* 函数名字.apply(对象,[参数1,参数2,...]);* 方法名字.apply(对象,[参数1,参数2,...]);* call的使用语法* 函数名字.call(对象,参数1,参数2,...);* 方法名字.call(对象,参数1,参数2,...);** 作用:改变this的指向* 不同的地方:参数传递的方式是不一样的** 只要是想使用别的对象的方法,并且希望这个方法是当前对象的,那么就可以使用apply或者是call的方法改变this的指向** */function f1() {console.log(this+":====>调用了");}//f1是函数,f1也是对象console.dir(f1);//对象调用方法,说明,该对象中有这个方法f1.apply();f1.call();console.log(f1.__proto__==Function.prototype);//所有的函数都是Function的实例对象console.log(Function.prototype);//ƒ () { [native code] }console.dir(Function);//apply和call方法实际上并不在函数这个实例对象中,而是在Function的prototype中function Person() {this.sayHi=function () {console.log("您好");};}Person.prototype.eat=function () {console.log("吃");};var per=new Person();per.sayHi();per.eat();console.dir(per);//实例对象调用方法,方法要么在实例对象中存在,要么在原型对象中存在

bind方法

 function f1(x, y) {console.log((x + y) + ":=====>" + this.age);}//复制了一份的时候,把参数传入到了f1函数中,x===>10,y===>20,null就是this,默认就是window//bind方法是复制的意思,参数可以在复制的时候传进去,也可以在复制之后调用的时候传入进去//apply和call是调用的时候改变this指向//bind方法,是赋值一份的时候,改变了this的指向//    var ff=f1.bind(null);//    ff(10,20);//    function Person() {
//      this.age = 1000;
//    }
//    Person.prototype.eat = function () {
//      console.log("这个是吃");
//    };
//    var per = new Person();
//
//    var ff = f1.bind(per, 10, 20);
//    ff();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 ff=per.play.bind(stu);ff();//bind是用来复制一份//使用的语法:/** 函数名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个函数* 方法名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个方法** */

bind方法的应用

 //通过对象,调用方法,产生随机数function ShowRandom() {//1-10的随机数this.number=parseInt(Math.random()*10+1);}//添加原型方法ShowRandom.prototype.show1=function () {//改变了定时器中的this的指向了,本来应该是window,现在是实例对象了window.setInterval(this.show2.bind(this),1000);};//添加原型方法ShowRandom.prototype.show2=function () {//显示随机数--console.log(this.number);};//实例对象var sr=new ShowRandom();//调用方法,输出随机数字//调用这个方法一次,可以不停的产生随机数字sr.show1();

函数的其他成员

1.name—>函数的名字,name属性是只读的,不能修改
2.arguments—>实参的个数
3.length—>函数定义的时候形参的个数
4.caller—>调用者

//函数中有一个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();

高阶函数

作为参数

 function f1(fn) {console.log("f1的函数");fn();//此时fn当成是一个函数来使用的}//fn是参数,最后作为函数使用了,函数是可以作为参数使用//传入匿名函数f1(function () {console.log("我是匿名函数");});//命名函数function f2() {console.log("f2的函数");}f1(f2);//函数作为参数的时候,如果是命名函数,那么只传入命名函数的名字,没有括号function f1(fn) {setInterval(function () {console.log("定时器开始");fn();console.log("定时器结束");},1000);}f1(function () {console.log("好困啊,好累啊,就是想睡觉");});

作为返回值

 //    function f1() {//      console.log("f1函数开始");//      return function () {//        console.log("我是函数,但是此时是作为返回值使用的");//      }////    }////    var ff=f1();//    ff();//    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(Object.prototype.toString.call(new Date()));//获取某个对象的类型是不是你传入的类型//[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);

作为参数的练习

//    var arr = [1, 100, 20, 200, 40, 50, 120, 10];//    //排序//    arr.sort();//    console.log(arr);
var arr = [1, 100, 20, 200, 40, 50, 120, 10];//排序---函数作为参数使用,匿名函数作为sort方法的参数使用,那么此时的匿名函数中有两个参数,arr.sort(function (obj1,obj2) {if(obj1>obj2){return -1;}else if(obj1==obj2){return 0;}else{return 1;}});console.log(arr);var arr1=["acdef","abcd","bcedf","bced"];arr1.sort(function (a,b) {if(a>b){return 1;}else if(a==b){return 0;}else{return -1;}});console.log(arr1);

作为返回值的练习

//排序,每个文件都有名字,大小,时间,都可以按照某个属性的值进行排序//三部电影,电影有名字,大小,上映时间function File(name, size, time) {this.name = name;//电影名字this.size = size;//电影大小this.time = time;//电影的上映时间}var f1 = new File("jack.avi", "400M", "1997-12-12");var f2 = new File("tom.avi", "200M", "2017-12-12");var f3 = new File("xiaosu.avi", "800M", "2010-12-12");var arr = [f1, f2, f3];function fn(attr) {//函数作为返回值return function getSort(obj1, obj2) {if (obj1[attr] > obj2[attr]) {return 1;} else if (obj1[attr] == obj2[attr]) {return 0;} else {return -1;}}}var ff = fn("name");//函数作为参数arr.sort(ff);for (var i = 0; i < arr.length; i++) {console.log(arr[i].name + "====>" + arr[i].size + "===>" + arr[i].time);}

函数闭包

作用域、作用域链、预解析

变量---->局部变量和全局变量,
作用域:就是变量的使用范围
局部作用域和全局作用域
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 num=10;}console.log(num);

作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了
层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错

 var num=10; //作用域链 级别:0var 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();

什么是闭包

闭包就是能够读取其他函数内部变量的函数,
由于在 Javascript 语言中,只有函数内部的子函数才能读取局部变量,
因此可以把闭包简单理解成 “定义在一个函数内部的函数”。
所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的用途:

  • 可以在函数外部读取函数内部成员
  • 让函数内成员始终存活在内存中
//闭包/** 闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这句话暂时不严谨)* 闭包的模式:函数模式的闭包,对象模式的闭包* 闭包的作用:缓存数据,延长作用域链* 闭包的优点和缺点:缓存数据** 闭包的应用*** *///函数模式的闭包:在一个函数中有一个函数function f1() {var num=10;//函数的声明function f2() {console.log(num);}//函数调用f2();}f1();//对象模式的闭包:函数中有一个对象function f3() {var num=10;var obj={age:num};console.log(obj.age);//10}f3();function f1() {var num=10;return function () {console.log(num);return num;}}var ff= f1();var result= ff();console.log(result);function f2() {var num=100;return {age:num}}var obj= f2();console.log(obj.age);

闭包案例

小案例

    //普通的函数function f1() {var num = 10;num++;return num;}console.log(f1());//11console.log(f1());//11console.log(f1());//11//函数模式的闭包function f2() {var num = 10;return function () {num++;return num;}}var ff = f2();console.log(ff());//11console.log(ff());//12console.log(ff());//13

案例产生多个相同的随机数

    function showRandom() {var num=parseInt(Math.random()*10+1);console.log(num);}showRandom();showRandom();showRandom();//闭包的方式,产生三个随机数,但是都是相同的function f1() {var num=parseInt(Math.random()*10+1);return function () {console.log(num);}}var ff=f1();ff();ff();ff();//总结:如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位置//闭包的作用:缓存数据.优点也是缺陷,没有及时的释放//局部变量是在函数中,函数使用结束后,局部变量就会被自动的释放//闭包后,里面的局部变量的使用作用域链就会被延长

案例点赞应用

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>对自己狠点</title><style>ul {list-style-type: none;}li {float: left;margin-left: 10px;}img {width: 200px;height: 180px;}input {margin-left: 30%;}</style><script>//$永远都是24k纯帅的十八岁的杨哥$</script>
</head>
<body>
<ul><li><img src="images/ly.jpg" alt=""><br/><input type="button" value="赞(1)"></li><li><img src="images/lyml.jpg" alt=""><br/><input type="button" value="赞(1)"></li><li><img src="images/fj.jpg" alt=""><br/><input type="button" value="赞(1)"></li><li><img src="images/bd.jpg" alt=""><br/><input type="button" value="赞(1)"></li>
</ul>
<script>//获取所有的按钮//根据标签名字获取元素function my$(tagName) {return document.getElementsByTagName(tagName);}//闭包缓存数据function getValue() {var value=2;return function () {//每一次点击的时候,都应该改变当前点击按钮的value值this.value="赞("+(value++)+")";}}//获取所有的按钮var btnObjs=my$("input");//循环遍历每个按钮,注册点击事件for(var i=0;i<btnObjs.length;i++){//注册事件btnObjs[i].onclick=getValue();}//  var btnObjs=my$("input");
//  var value=1;
//  //循环遍历每个按钮
//  for(var i=0;i<btnObjs.length;i++){
//
//    //为每个按钮注册点击事件
//    btnObjs[i].onclick=function () {
//      console.log("哈哈");
//      this.value="赞("+(value++)+")";
//    };
//  }
</script>
</body>
</html>

沙箱

环境,黑盒,在一个虚拟的环境中模拟真实世界,做实验,实验结果和真实世界的结果是一样,但是不会影响真实世界

   var num=100;(function () {var num=10;console.log(num);//10}());console.log(num);//100

沙箱案例

<div>这是div</div>
<div>这是div</div>
<div>这是div</div>
<p>这是p</p>
<p>这是p</p>
<p>这是p</p>
<script>var getTag = 10;var dvObjs = 20;var pObjs = 30;//放进沙箱里 变量的命名就不会冲突了(function () {//根据标签名字获取元素function getTag(tagName) {return document.getElementsByTagName(tagName)}//获取所有的divvar dvObjs = getTag("div");for (var i = 0; i < dvObjs.length; i++) {dvObjs[i].style.border = "2px solid pink";}//获取所有的pvar pObjs = getTag("p");for (var i = 0; i < pObjs.length; i++) {pObjs[i].style.border = "2px solid pink";}}());console.log(getTag);console.log(dvObjs);console.log(pObjs);

递归

函数中调用函数自己,此时就是递归,递归一定要有结束的条件

    var i = 0;function f1() {i++;if (i < 5) {f1();}console.log("从前有个山,山里有个庙,庙里有个和尚给小和尚讲故事:");}f1();

递归案例

    //求n个数字的和,5 计算1+2+3+4+5
//    var sum=0;
//    for(var i=1;i<=5;i++){
//      sum+=i;
//    }
//    console.log(sum);//递归实现:求n个数字的和   n=5--->  5+4+3+2+1//函数的声明function getSum(x) {if(x==1){return 1;}return x+getSum(x-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**** *///递归案例:求一个数字各个位数上的数字的和:  123   --->6 ---1+2+3//523function getEverySum(x) {if(x<10){return x;}//获取的是这个数字的个位数return x%10+getEverySum(parseInt(x/10));}console.log(getEverySum(1364));//5//递归案例:求斐波那契数列function getFib(x) {if(x==1||x==2){return 1}return getFib(x-1)+getFib(x-2);}console.log(getFib(12));

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/898.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息