从零开始学 Web 之 JS 高级(三)apply与call,bind,闭包和沙箱
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新......
- github:https://github.com/Daotin/Web
- 微信公众号:Web前端之巅
- 博客园:http://www.cnblogs.com/lvonve/
- CSDN:https://blog.csdn.net/lvonve/
在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目。现在就让我们一起进入 Web 前端学习的冒险之旅吧!
一、apply 和 call 方法
apply 和 call 都可以改变调用其的函数或方法中的 this 指向。
不同的是传入参数时,apply 有两个参数,第二个参数是数组;call 从第二个参数开始是调用其的函数的所有参数。
使用方法:
1、apply的使用语法:
函数名.apply(对象,[参数1, 参数2,... ]);
方法名.apply(对象,[参数1, 参数2,... ]);
2、call的使用语法:
函数名.call(对象,参数1, 参数2,... );
方法名.call(对象,参数1, 参数2,... );
1、函数调用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
2、方法调用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 构造函数的原型对象中。
二、bind方法
bind 是复制的意思,也可以改变调用其的函数或方法的 this 指向,参数可以在复制的时候传进去,也可以在复制之后调用的时候传进去。
使用语法:
1、函数名.bind(对象, 参数1, 参数2, ...); // 返回值是复制的这个函数
2、方法名.bind(对象, 参数1, 参数2, ...); // 返回值是复制的这个方法
1、函数调用 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);
2、方法调用 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);
三、闭包
1、闭包的概念
有一个函数 A 中有一个函数或者对象 B,那么函数或者对象 B 可以访问函数 A 中的数据,那么函数 A 的作用域就形成了闭包。
2、闭包的模式
函数模式的闭包:函数中包含函数。
对象模式的闭包:函数中包含对象。
3、闭包的作用
缓存数据,延长作用域链。
4、闭包的优缺点
也是缓存的数据,导致在闭包的范围内一直起作用。
5、闭包的应用
缓存数据,函数中的数据,外面可以使用。
如果想要缓存数据,就把这个数据放在外层的函数和里层的函数之间。这样不停的调用里层函数,相当于外层函数里的数据没有得到及时释放,就相当于缓存了数据。
// 函数闭包
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);
四、沙箱
沙箱:一小块的真实环境,里面发生的事情不会影响到外面。相同的操作,相同的数据都不会和外面发生冲突。
作用:避免命名冲突。
比如:自调用函数里面就相当于一个沙箱环境。
(function (){
}());
五、区分伪数组和真数组
// 真数组
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]);
}
方法一、使用 length 来区分
这样看起来,真数组和伪数组就没法区别了。
但是真数组的长度 length 可以改变,伪数组不可以,貌似可以区分了。
但是,你还记得有个 arguement 这个伪数组(对象)的 length 是可以改变的,方法一区分失败。
方法二、使用数组的方法 forEach 来鉴别
因为每个数组都是 Array 的实例对象,而 forEach 在 Array 的原型对象中,所以其他的伪数组是不能使用的。方法二成功。
从零开始学 Web 之 JS 高级(三)apply与call,bind,闭包和沙箱的更多相关文章
- 从零开始学 Web 之 JS 高级(二)原型链,原型的继承
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- 从零开始学 Web 之 HTML(三)表单
大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...
- 从零开始学 Web 之 JavaScript(三)函数
大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...
- 从零开始学 Web 之 BOM(三)offset,scroll,变速动画函数
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- 从零开始学 Web 之 JavaScript 高级(一)原型,贪吃蛇案例
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- 从零开始学 Web 之 CSS(三)链接伪类、背景、行高、盒子模型、浮动
大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...
- 从零开始学 Web 之 DOM(三)innerText与innerHTML、自定义属性
大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...
- 从零开始学 Web 之 jQuery(三)元素操作,链式编程,动画方法
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- 从零开始学 Web 之 Ajax(三)Ajax 概述,快速上手
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
随机推荐
- vue 总结
VUE总结 双花括号{{}} 01.index.hmlt main.js 内存的数据可以更改 v-model 双休数据绑定 代码: <!DOCTYPE html> <html lan ...
- python08内置函数
https://www.cnblogs.com/xiao1/p/5856890.html 1 .all(可迭代对象),对每个元素进行布尔运算,全部为真,函数结果就为真,否则为假 参数为一个整体的情况例 ...
- 【微信小程序开发】全局配置
今天看看小程序全局配置. 上一篇[微信小程序开发]秒懂,架构及框架 配置,无非就是为了增加框架的灵活性,而定下的规则. 微信小程序的配置文件是一个树状结构,各个节点代表不同的配置项,小程序框架会解析这 ...
- tensorflow学习之(五)构造简单神经网络 并展示拟合过程
# def 添加层 如何构造神经网络 并展示拟合过程 import tensorflow as tf import numpy as np import matplotlib.pyplot as pl ...
- delphi 中record 的类操作符重载简介
今天简单介绍一下 delphi 中record 的类操作符重载使用,就是如何 实现 record 之间的简单操作. 关于类操作符重载 ,大家可以看官方的文档. Delphi allows certai ...
- Apache Thrift的C++多线程编程定式
Facebook贡献给Apache的开源RPC组件Thrift有着广泛的应用,C++中使用Thrift也十分普遍,但由于Thrift的Handler会被多个线程调用,因而多线程中应用并不直接的友好,利 ...
- STM32F1xx寄存器版库
文件下载链接 https://files.cnblogs.com/files/listenscience/STM32F1xx%28MDK5%292018.10.20.rar
- EF6学习笔记(六) 创建复杂的数据模型
EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本篇原文地址:Creating a More Complex Data Model 本篇讲的比较碎,很多内容本人 ...
- FPGA的发展史及FPGA 的基础架构
通过了解早期FPGA的发展,理解FPGA究竟是干什么的,FPGA到底在电子设计领域起到了什么样的作用,下面是一张早期的设计过程 早期的设计流程过程中,只有当硬件完成了才能够得到功能的验证,随着集成电路 ...
- 26、TCP服务器原理
TCP / IP的工作 TCP / IP是Internet上使用的网络协议.它是协议,ESP32本身自带了TCP/IP协议,所以,我们只需了解并学会运用即可. 首先,有IP地址.这是一个32位值,应该 ...