apply和call方法的使用
//apply和call的使用
//作用:可以改变this的指向
//apply和call方法中如果没有传入参数,或者是传入的是null,那么调用该方法的函数对象中的this就是默认的window
*JavaScript中存在继承,通过调用apply或call传过去的第一个参数来动态指定方法中的 this .
function f1(x,y) {console.log("结果是:"+(x+y)+this);return "10000";}f1.apply();f1.call();f1.apply(null);f1.call(null);apply和call都可以让函数或者方法来调用,传入参数和函数自己调用的写法不一样,但是效果是一样的f1.apply(null,[100,200]);f1.call(null,100,200);
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也是对象,因为f1中有 __proto__和prototypeconsole.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中
bind是用来复制一份 //使用的语法: /*理解:将改变this后的函数状态复制了一份。函数调用之后内部this使用的是指定后的 * 函数名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个函数 * 方法名字.bind(对象,参数1,参数2,...);---->返回值是复制之后的这个方法
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(); [object Object]====>20
bind方法的使用
<script>通过对象,调用方法,产生随机数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();</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);//调用者}
函数还可以通过参数传递来实现调用,在函数体中执行函数
function f1(fn) {setInterval(function () {console.log("定时器开始");fn();console.log("定时器结束");},1000);}f1(function () {console.log("好困啊,好累啊,就是想睡觉");});
函数作为返回值
可以参考java中设置toString方法进行理解var num=10;console.log(typeof num); numbervar obj={};console.log(obj instanceof Object); true更改this为obj,直接打印obj的使用会显示其数据类型Object.prototype.toString.call(obj);console.log(obj) {}获取数据类型,修改this指向具体类型数据,通过toString方法进行打印console.log(Object.prototype.toString.call([])); [object Array]console.log(Object.prototype.toString.call(new Date())); [object Date]函数作为返回值的使用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); true
函数作为参数练习,有点像java中的重写equals方法
*sort方法会从零号位置进行遍历和比较,如果返回值大于零,则进行交换。
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中没有块级作用域---一对括号中定义的变量,这个变量可以在大括号外面使用
//函数中定义的变量是局部变量
if(true){var num=10;}console.log(num) 10function fn() {var num2=20;}console.log(num2); 报异常 num2 is not defined
作用域链:变量的使用,从里向外,层层的搜索,搜索到了就可以直接使用了层层搜索,搜索到0级作用域的时候,如果还是没有找到这个变量,结果就是报错
*如果里层没有对应的变量,它会一层一层想外查找
var num=10;function f() {var num=20;function f1() {var num=30;console.log(num);}f1();}f();
//预解析:就是在浏览器解析代码之前,把变量的 声明 和 函数的声明 提前(提升)到该作用域的最上面
console.log(num);var num=10; undefined 声明提前了,但是没有初始化f(); 函数执行了,预解析函数提前了function f() {console.log('函数执行了')}console.log(f1); undefined 函数的声明提前了var f1=function() {console.log('声明提前了')}
闭包
* 闭包的概念:函数A中,有一个函数B,函数B中可以访问函数A中定义的变量或者是数据,此时形成了闭包(这句话暂时不严谨)
* 闭包的模式:函数模式的闭包,对象模式的闭包
* 闭包的作用:缓存数据,延长作用域链
* 闭包的优点和缺点:缓存数据
函数模式的闭包:在一个函数中有一个函数function f1() {var num=10;//函数的声明function f2() {console.log(num); 10}//函数调用f2();}f1();对象模式的闭包:函数中有一个对象function f3() {var num=10;var obj={age:num};console.log(obj.age);//10}f3();
闭包小练习
function f() {var num=10;return function(){num++;return num;}}var fn=f();console.log(fn()); 11console.log(fn()); 12console.log(fn()); 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();
案例:点赞小案例
<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>...若干个...
</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 num=10;(function () {var num=20;console.log(num+10); 30})();
沙箱小案例
(function () {document.getElementById('btn').onclick=function () {console.log('按钮被点击了')}})();(function () {var str='我是中国人';console.log(str.substr(2)) 中国人})();
沙箱小案例
<div>这是div</div>
<div>这是div</div>
<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); 10console.log(dvObjs); 20console.log(pObjs); 20
递归:函数中调用函数自己,此时就是递归,递归一定要有结束的条件
function f(n) {if(n==1){return 1;}return n+f(n-1);}console.log(f(10));
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态