你们好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新......前端
- github:https://github.com/Daotin/Web
- 微信公众号:Web前端之巅
- 博客园:http://www.cnblogs.com/lvonve/
- CSDN:https://blog.csdn.net/lvonve/
在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目。如今就让咱们一块儿进入 Web 前端学习的冒险之旅吧!git
1、apply 和 call 方法
apply 和 call 均可以改变调用其的函数或方法中的 this 指向。github
不一样的是传入参数时,apply 有两个参数,第二个参数是数组;call 从第二个参数开始是调用其的函数的全部参数。数组
使用方法:缓存
一、apply的使用语法:微信
函数名.apply(对象,[参数1, 参数2,... ]);闭包
方法名.apply(对象,[参数1, 参数2,... ]);app
二、call的使用语法:函数
函数名.call(对象,参数1, 参数2,... );学习
方法名.call(对象,参数1, 参数2,... );
一、函数调用apply和call
function f1(x, y) { console.log(x+y +this); // 这里面的this是window return x+y; } var r1 = f1.apply(null, [10,20]); // 打印30 window,传入的是null,因此this指向仍是window console.log(r1); // 30 var r2 = f1.call(null, 10,20);// 打印30 window console.log(r2); // 30
//函数改变 this 的指向 var obj = {}; var r1 = f1.apply(obj, [10,20]); // 打印30 window,传入的是Obj,因此this指向是Obj console.log(r1); // 30 var r2 = f1.call(obj, 10,20);// 打印30 Obj console.log(r2); // 30
二、方法调用apply和call
// 方法改变 this 的指向 function Person(age) { this.age = age; } Person.prototype.eat = function () { console.log(this.age); // this 指向实例对象 }; function Student(age) { this.age = age; } var per = new Person(18); var stu = new Student(20); per.eat.apply(stu); // 打印 20 per.eat.call(stu); // 打印 20
因为 eat 方法已经指向了 Student 了,因此打印 20,而不是 18.
问题:咱们知道函数也是对象,函数能够调用 apply 和 call 方法,可是这两个方法并不在这个函数这个对象的实例函数中,那么在哪里呢?
解答:全部的函数都是 Function 的实例对象,而 apply 和 call 就在 Function 构造函数的原型对象中。
2、bind方法
bind 是复制的意思,也能够改变调用其的函数或方法的 this 指向,参数能够在复制的时候传进去,也能够在复制以后调用的时候传进去。
使用语法:
一、函数名.bind(对象, 参数1, 参数2, ...); // 返回值是复制的这个函数
二、方法名.bind(对象, 参数1, 参数2, ...); // 返回值是复制的这个方法
一、函数调用 bind
function f1(x, y) { console.log(x + y + this); } // 1.参数在复制的时候传入 var ff = f1.bind(null,10,20); // 这只是复制的一份函数,不是调用,返回值才是 ff(); // 2.参数在调用的时候传入 var ff = f1.bind(null); // 这只是复制的一份函数,不是调用,返回值才是 ff(10,20);
二、方法调用 bind
function Person(age) { this.age = age; } Person.prototype.eat = function () { console.log(this.age); // this 指向实例对象 }; function Student(age) { this.age = age; } var per = new Person(18); var stu = new Student(20); var ff = per.eat.bind(stu); ff(); // 20
bind和call,apply的区别:[update:2018.07.26]
bind绑定this的指向以后,不会当即调用当前函数,而是将函数返回。 而call,apply绑定this指向后会当即调用。
若是咱们在不知道何时会调用函数的时候,须要改变this的指向,那么只能使用bind。
好比:在定时器中,咱们想改变this的指向,可是又不能当即执行,须要等待2秒,这个时候只能使用bind来绑定this。
setInterval(function(){ // ... }.bind(this), 2000);
3、闭包
一、闭包的概念
有一个函数 A 中有一个函数或者对象 B,那么函数或者对象 B 能够访问函数 A 中的数据,那么函数 A 的做用域就造成了闭包。
二、闭包的模式
函数模式的闭包:函数中包含函数。
对象模式的闭包:函数中包含对象。
三、闭包的做用
缓存数据,延长做用域链。
四、闭包的优缺点
也是缓存的数据,致使在闭包的范围内一直起做用。
五、闭包的应用
缓存数据,函数中的数据,外面可使用。
若是想要缓存数据,就把这个数据放在外层的函数和里层的函数之间。这样不停的调用里层函数,至关于外层函数里的数据没有获得及时释放,就至关于缓存了数据。
// 函数闭包 function A() { var num = 10; return function () { return num++; } } var func = A(); console.log(func()); console.log(func()); console.log(func());
// 对象闭包 function A() { var num = 10; return { age: num++ }; } var func = A(); console.log(func.age);
4、沙箱
沙箱:一小块的真实环境,里面发生的事情不会影响到外面。相同的操做,相同的数据都不会和外面发生冲突。
做用:避免命名冲突。
好比:自调用函数里面就至关于一个沙箱环境。
(function (){ }());
5、区分伪数组和真数组
// 真数组 var arr = [10,20,30]; // 伪数组 var obj = { 0:10, 1:20, 2:30, length: 3 }; // 真数组的访问 for(var i=0; i<arr.length; i++) { console.log("真数组的访问:"+arr[i]); } // 伪数组的访问 for(var j=0; j<obj.length; j++) { // 错误:对象中没有length方法 console.log("伪数组的访问:"+obj[j]); }
方法1、使用 length 来区分
这样看起来,真数组和伪数组就无法区别了。
可是真数组的长度 length 能够改变,伪数组不能够,貌似能够区分了。
可是,你还记得有个 arguement 这个伪数组(对象)的 length 是能够改变的,方法一区分失败。
方法2、使用数组的方法 forEach 来鉴别
由于每一个数组都是 Array 的实例对象,而 forEach 在 Array 的原型对象中,因此其余的伪数组是不能使用的。方法二成功。