本文共 4435 字,大约阅读时间需要 14 分钟。
一、全局作用域
在函数外部定义的变量或函数,叫全局变量或全局函数。它们可以在当前程序的任意位置使用。在全局中定义变量可以用var,也可以直接添加window的属性。
生命周期:它们会一直占用内存,只能在当前文件中使用。如果想在多个文件中使用变量,需要用到cookie或本地存储。
例1 测试全局作用域
Document
二、局部作用域
在函数内部定义的变量或函数,叫局部变量或局部函数。它们只能在函数内部使用。在函数内部用var定义局部变量,如果用window定义的变量,则为全局变量。
生命周期:从调用时开始创建,到函数执行完后立即销毁。
例2 测试局部作用域
Document
三、块级作用域
在ES5中没有块级作用域,ES6中有。一对{ }为一个块,块级作用域就是变量或函数只在当前这组{}中有效。在ES5中可以用IIFE实现块级作用域,ES6中用let实现。
四、IIFE
1、什么是IIFE?
IIFE(Immediately Invokeed Function Expression:立即执行函数表达式),声明函数的同时立即执行调用这个函数。定义的函数没有函数名,只能执行一次,无法在其它地方被调用,也不会造成全局污染。
2、IIFE的作用
可以用于解决运算中产生的全局污染问题(实际上它是一个闭包的写法)。它也是ES5中实现块级作用域的方式。
3、IIFE和特点
(1)将所有运算代码都放在匿名函数中; (2)函数是一个表达式,没有函数名,只能被执行一次; (3)执行一次后所产生的数据和变量就立即销毁,不会造成全局污染。4、IIFE语法
(function(params){
... })(exprs)将函数的定义和调用写在一起。
5、IIFE的用法(推荐用前面两种写法)
(function(形参列表){
... window.变量 = 表达式; })(实参列表);例3 测试第一种写法 计算1+2+3+...+100
Document
var 变量名 = (function(形参列表){
... return 表达式; })(实参列表);例4 测试第二种写法 计算1+2+3+...+100
Document
!(function(形参列表){
... return 表达式; })(实参列表);+(function(形参列表){
... return 表达式; })(实参列表);
五、闭包
1、什么是闭包?
闭包就是一种作用域的体现,函数外部可以访问函数内部的数据。正常情况下,函数外部不能访问函数内部的变量,但是通过这种特殊的写法,将函数内的子函数暴露在全局上,可以在外部调用且可以访问到函数内部的数据,即可以让全局访问局部的数据。
简单地说:就是在函数外部获取函数内部的数据。
2、闭包的作用
(1)实现函数外部可以访问函数内部的数据;
(2)减少了全局变量的使用,避免全局变量的污染。
3、闭包的特点
(1)闭包一定是函数内嵌套函数; (2)闭包是一种作用域的体现,函数外可以访问函数内的数据; (3)闭包采用IIFE写法,由于内部数据被全局所调用,将延缓资源的回收(即闭包中的变量的值用完后不会立即销毁,会驻留内存一段时间)。4、闭包的缺点
(1)闭包中的变量会占用更多的内存空间; (2)可能会导致内存泄露。5、闭包的写法
第1种写法:
(function(){ ... window.函数名 = function(){ ... return 变量; } })()例5 测试第一种写法
Document
第2种写法:
var 变量 = (function(){ ... return function(){ ... return 变量; } })()例6 测试第二种写法
Document
六、内存管理
在闭包中调用局部变量,会导致这个局部变量无法及时被销毁,相当于全局变量一样会一直占用着内存。如果需要回收这些变量占用的内存,可以手动将变量设置为null。然而在使用闭包的过程中,比较容易形成 JavaScript 对象和 DOM 对象的循环引用,就有可能造成内存泄露。这是因为浏览器的垃圾回收机制中,如果两个对象之间形成了循环引用,那么它们都无法被回收。
解决方案:
(1)把循环引用中的变量设为 null 即可; (2)把闭包写法改造成一个引用外部函数写法。例7 测试内存管理
Document box
七、JavaScript对象
对象分为内置对象(构造函数/方法)和用户自定义对象。
1、内置对象:String Date Math RegExp Function Object Array Boolean Number...
var str1 = new String('abc');// 类型为object var str2 = 'abc' // 类型为string2、用户自定义对象
(1)字面量
var obj1 = { name: 'aaa', sex: 'male' }(2)用new构建
var obj2 = new Object({ name: 'aaa', sex: 'male' })(3)构造函数(相当于ES6中类)
a.创建方法
function 构造函数名/类名(形参列表){ // 类的特征-属性 this.属性名 = 参数; ...// 类的形为-方法
this.方法名 = function(){ ... } ... } b.使用构造函数实例化对象 var 对象名 = new 构造函数名/类名(实参列表) c.构造函数特征 i)构造函数名(类名)首字母要大写(W3C的规定)(要使用大驼峰写法);补充:
小驼峰写法:studentClassicScore 大驼峰写法:StudentClassicScore ii)属性和方法都要挂载到this上; iii)没有return语句。 d.实例化机制 i)创建一个对象; ii)将构造函数中的this指向新对象; iii)执行构造函数中的语句,将所有的属性和方法挂载到新的对象上; iv)把新的对象的内存地址赋值给变量。 e.问题 如果构造函数实例化的对象中的属性和方法的内容一样,因为它们会各自占用独立的空间,会造成内存的浪费。例8 构造函数
Document
4、原型
a.什么上原型? 原型就是prototype,所有function定义的函数都拥有这个属性。 prototype这个属性是一个对象,也是一个指针,是用来添加所有实例共享属性和方法的。 b.原型的作用 i)解决方法过载(为每个对象都单独创建一个方法,浪费了大量的内存资源,这种情况叫方法过载); ii)扩展构造函数的属性和方法(功能)。 c.原型的写法 i)扩展属性 构造函数名.prototype.属性名 = 表达式; ii)扩展方法 构造函数名.prototype.方法名 = function(){ ... } 注意:在开发过程中,私有属性和方法放在构造函数中,而共享属性和方法用原型添加。例9 原型
5、混合模式Document
混合模式 = 构造函数 + 原型
在构造函数中定义私有的属性和方法,通过原型添加共享的属性和方法。例10 混合模式
Document
6、基本模式(JSON语法格式)
var 对象 = { 属性:属性值, ..., 方法:function(){...}, ... }这样做的目的是为了减少全局变量和全局方法的使用,从而避免全局污染。
例11 基本模式
Document idclasspppppp
pppppp
pppppp
7、工厂模式
一般用于大批量创建对象(这批对象有相同的属性和方法)。给定一些值,创建一个结果。
a.创建方法:
创建一个函数,在函数中创建对象,最后再返回这个对象。b.缺陷
让不同对象有不同属性或方法,工厂模式就很难实现了。c.优点
减少了重复性代码。混合模式(构造函数+原型)在ECMAScript中是使用最广泛、认同度最高的一种创建自定义对象的方法。
例12 工厂模式
Document
八、this(面试核心点)
this是一个地址指针。
1、全局中的this,指向window对象。
Document
2、函数中的this
原则:谁调用就指向谁。一般情况下是指向window对象的。Document
如果开启了"use strict;"严格代码格式,this指向的是window。
Document
3、对象方法中的this,指向当前对象。
Document
4、构造函数中的this,指向当前实例化的对象。
Document
5、借来的this,所有函数都有三个方法(call、apply和bind),可以用它们实现函数中this指向新的对象(修改函数中this的指向)。
(1)call:主动式将函数中的this指向新的对象,调用一次就立即执行一次(谁调用就指向谁)。
语法:被调用对象的方法.call(当前对象,参数1,参数2,...)
Document
(2)apply
用法与call一样,只是传参格式不一样。传参必须以伪数组的方式传递,不管有几个参数,都必须以这种格式进行传递。
语法:被调用对象的方法.apply(当前对象,[参数1,参数2,...])
Document
(3)bind(ES5新增)
被动式改变this指向,实现对原对象的拷贝。
语法:回调函数.bind(对象,参数1,参数2,...)
Document
6、call、apply和bind的区别
相同点:
i)都是函数原型的方法,可以改变函数中this的指向; ii)第一个参数都是this要修改的目标对象; iii)都可以传递参数。不同点:
i)call和apply是主动式的,修改this指向时立即调用1次; ii)bind是被动式的,只修改this的指向,不执行; iii)call的参数是直接列举在对象的后面,而apply是以伪数组的形式传参; iv)bind一般用在回调函数中。转载地址:http://sfvrn.baihongyu.com/