《JS高级程序设计》[4-5]

《JavaScript高级程序设计》Nicholas C.Zakas著


第4章 变量、作用域和内存问题

4.1基本类型和引用类型的值

ES的变量分为基本类型值(包括String),引用类型值。
JS不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。
不能给基本类型的值添加属性,虽然不会报错,但是你访问它的属性时发现消失了。

复制变量

从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。

当复制引用类型的值是,执行同样的操作,只不过,这个值的副本实际上是个指针,这个指针指向存储在堆中的一个对象。

参数传递
函数所有参数都是按值传递,也就是说和复制变量是一样的。

function setName(obj){
    obj.name = "miao";
    obj = new Object();
    obj.name = "wang";
}
var person = new Object();
setName(person);
alert(person.name); //结果为miao,此例证明了对于引用类型也是按值传递,不过这个值是个指向对象的指针。

检查类型
typeof操作符检测类型 typeof s;//string
instanceof操作符检测变量是否是给定引用类型的实例。s instanceof Object;//true

4.2 执行环境及作用域

执行环境

简称环境,定义了变量或函数有权访问的其他数据,决定了它们各自的行为。

此处语义模糊,我个人推测应该是——
变量或函数的环境定义了它们有权访问的其他数据。
此处的变量具体地说应该是对象(它所能访问的数据就是它的属性)。
执行环境指的就是它们的内部。

某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。

全局执行环境
最外围的一个执行环境,在web浏览器中,全局执行环境被认为是window对象。

变量对象
每个执行环境都有一个与之关联的变量对象,保存了定义在环境中的所有变量和函数。

作用域链
当代码在一个环境中执行时,会创建变量对象的一个作用域链。
作用域链的作用是保证执行环境有权访问的所有变量和函数的有序访问。
作用域链的前端始终是当前执行的代码所在的环境的变量对象;下一个变量对象来自外部(包含)函数;全局执行环境始终是末端。
标识符解析是沿着作用域链一级一级地搜索标识符的过程,如果找到就停止搜索。

延长作用域链
with语句或try-catch语句的catch块可以在作用域链的前端临时增加一个变量对象。

没有块级作用域
换句话说,JS不同于类C语言,一对花括号不能自成作用域。

if(true){
    var color = "blue";
}
alert(color);//blue

在使用for时尤其要牢记这一差异。

var声明的变量会自动添加到最接近的环境中。如果没有使用var声明,则该变量会自动地添加到全局环境中,因为这样可能会导致意外,所以建议在初始化变量之前,一定要进行声明。

4.3垃圾回收

垃圾收集机制的原理:找出那些不再继续使用的变量,然后释放其占用的内存。

标记清除
JS中最常用的垃圾收集方式。
当变量进入环境时,将这个变量标记为“进入环境”。从逻辑上讲,永远不够释放进入环境的变量所占的内存。

引用计数
当声明一个变量并将一个引用类型的值赋给该变量时,引用次数+1;
当同一个值被赋给另一个变量时,则该值的引用次数+1;
包含这个值引用的变量又取得了另外一个值,则这个值的引用次数-1;
引用次数为0则可以被回收。
但是这种方法存在着循环引用(两个对象的属性的值互为对方时),无法回收。

解除引用

优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其设置为null。

解除一个值的引用并不意味这自动回收该值所占用的内存。解除引用的真正作业是让值脱离执行环境,以便垃圾收集器下次运行时将其收回。


第5章 引用类型

虽然引用类型与类看起来相似,但它们并不是相同的概念。(它不具备传统的面向对象语言所支持的类和接口等基本结构。)

5.1 Object类型

创建Object实例的方法有两种:

  • new操作符后跟Object构造函数
  • 使用对象字面量表示法

对于函数的参数,建议必需值使用命名参数,使用对象字面量来封装多个可选参数。

访问对象属性有两种方法:

  • 点表示法:person.name
  • 使用方括号:person[name] 方括号中可以是直接的字符串,也可是保存了字符串的变量,当然也可以是属性名。除非必要不推荐使用这种方式来访问属性。

5.2 Array类型

ES的数组每一项可以保存任何类型的数据,并且数组的大小可以动态地改变。

如果设置某个值的索引超过了数组现有项数,数组就会自动增加到该索引值加1的长度。
对于length属性,它是可以人为地修改的。通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项。

检测数组
使用Array.isArray()方法检测一个值是不是数组(不使用instanceof操作符的原因是,该操作符假定只存在一个全局执行环境。如果网页中包含多个框架,那实际上存在两个以上不同的全局执行环境,从而存在两个以上不同版本的Array构造函数。)

转换方法
.toString() 返回数组中每个值的字符串拼接而成的一个以逗号分隔的字符串。
.valueOf() 返回的还是数组。
.join() 接收一个参数,用作分隔符的字符串,不传入值或传入undefined值时,则使用逗号作为分隔符。

栈方法:.push()、.pop()在数组后端取出项
队列方法:.push()、.shift()在数组前端取出项、.unshift()在数组前端加入项

重排序方法
.reverse() 翻转数组。
.sort()按升序排列数组,但是比较的是字符串,即使数组中的每一项都是数值。
.sort(比较函数),比较函数的规则则为排序规则。比较函数有两个参数,对于A、B两项,若返回值为-1,则A在B之前,若返回值为0,则A,B同样大小,若返回值为1,则A在B之后。

操作方法
.concat() 将某个数组同其余数组或单项拼接在一起。原数组不变,返回值是拼接好的数组。
.slice() 从某个数组中获取一个子数组。如果传入一个参数,则以该参数指定位置为起始位置一直到数组在最后一位,如果传入两个参数,则一直到第二参数对应项的前一项。原数组不变,返回值是取出的子数组。如果参数为负数,则加上数组长度。如果结束位置小于起始位置,则返回空数组。
.splice()
删除:参数A指定要删除的第一项的位置,参数B要删除的项数。
插入:参数A起始位置,参数B:0(要删除的项数),要插入的项1,2,3,……
替换:参数A起始位置,参数B(要删除的项数),要插入的项1,2,3,…
原数组变为操作后的数组,返回值包含从原始数组中删除的项,如果没,就是个空数组。

位置方法
.indexOf() .lastIndexOf()
两个参数,A:要查找的项,B:查找起点位置的索引(可选)。一个从前往后,一个从后往前。返回值为查找项在数组中的位置,没有返回-1。比较是用全等。

迭代方法
.every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
some():对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
.filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
.map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
.forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
以上方法都接收两个参数:要在每一项上运行的函数和(可选的)运行该函数的作用域对象(影响this的值)
传入的方法有3个参数,分别代表:数组项的值,该项在数组中的位置,数组对象本身。

归并方法
.reduce() .reduceRight():迭代数组的所有项,构建一个最终的返回值。前者从第一项开始,后者从最后一项开始。
两个方法都接收两个参数:在每一项上的运行的处理函数,(可选的)作为归并基础的初始值。
处理函数有4个参数,分别代表:前一个值(上次执行时函数的返回值),当前值,项的索引和数组对象。

5.3 Date类型

var now = new Date(); 获得当前时间

  • 参数可以是Number,毫秒数。
  • 可以是一个表示日期的字符串参数(后台会调用Date.parse()将参数转换为毫秒,对于Date.parse()方法,如果传入的字符串不能表示日期,返回NaN)
  • 可以是一系列的参数,分别表示年月[0-11]日[1-31]时[0-23]分秒(后台会调用Date.UTC()将参数转换为毫秒,对于Date.UTC(),前两个参数是必须的,省略天数则默认为1,省略其他则默认为0)

Date.now(); 返回表示调用这个方法时的日期和时间的毫秒数。
Date类型的valueOf()方法,返回的也是毫秒数。
Date类型的toString()方法,由于各个浏览器的实现不同,展示的格式都不同。

getTime()、getFullYear(),getMonth(),getDate(),getDay(),getHours(),getMinutes(),getSeconds()

5.4 RegExp类型

var expression = / pattern / flags;
//pattern正则表达式
//flags标志,g全局,查找所以而非第一个匹配项;i不区分大小写;m多行模式。
var expression = new RegExp("pattern","flags");
//注意:该模式的参数是字符串,所以在某些情况下要对字符进行双重转义
var ex0 = /[bc]at/g;   //匹配所有cat或bat
var ex1 = /\[bc\]at/g; //匹配所有[bc]at
var ex2 = new RegExp("\\[bc\\]at","g"); //匹配所有[bc]at

RegExp的实例属性
是否设置了三个标志。
lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从0算起。
source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。

RegExp的实例方法
exec()接受一个要应用模式的字符串,然后返回包含第一个匹配项信息的数组;没有则返回null(专为捕获组设计)
返回的Array数组,包含两个属性:
index:匹配项在字符串中的位置。
input:应用正则表达式的字符串。
数组第一项:与整个模式匹配的字符串。
数组其他项:与模式中的捕获组匹配的字符串。
注意:即使在模式中设置了全局标志g,它每次也只会返回一个匹配项,但会在下次调用时,在字符串中查找新的匹配项,并且lastIndex在每次调用exec()后都会增加。

test()在模式与该参数匹配的情况下返回true;否则,返回false。

RegExp构造函数属性
(其他语言中被称为静态属性)
RegExp.xxx

长属性名说明
input最近一次要匹配的字符串,Opera未实现
lastMatch最近一次的匹配项,Opera未实现
lastParen最近一次匹配的捕获组
leftContentinput字符串中lastMatch之前的文本
multiline布尔值,表示是否所有表达式都使用多行模式,IE和Opera均未实现
rightContentInput字符串中lastMatch之后的文本
$1…$99个用于存储捕获组的构造函数属性


模式存在局限性,不支持部分高级正则表达式特性。

5.5 Function类型

函数实际上是对象,每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

function sum(a,b){}
var sun = function(a,b){};  //注意有个分号!
var sum = new Function("num1","num2","return num1 + num2"); //不推荐,二次解析:解析常规ECMAScript代码,解析传入构造函数中的字符串),从而影响性能。

函数声明与函数表达式
上第一种定义方法为函数声明,第二种为函数表达式。
唯一区别:解析器会率先读取函数声明,并使其在执行任何代码之前可用。对于函数表单时,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

作为值的函数
要访问函数的指针而不执行函数的话,必须去掉函数名后的圆括号。(所以在之前的排序的sort()中的对比函数作为参数时,就没有后面的括号)

函数内部属性
arguments 主要用途是保存函数参数。这个对象还有一个名叫callee的属性,是一个指针,指向拥有这个arguments对象的函数。
在递归函数中,如果在函数内部直接使用函数名,这种紧密的耦合会在引用的函数名发生变化时,不得不修改内部的代码,所以用arguments.callee更好。
函数内部的另一个特殊对象是this,引用的是函数执行的环境对象。
另一个函数对象的属性:caller,保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null。

函数属性和方法
length属性:函数希望接收的命名参数的个数。
prototype属性:保存它们所有实例方法的真正所在。(该属性在ES5中不可枚举,故使用for-in无法发现)
.apply()方法:在特定作用域中调用函数。参数1指定作用域,参数2指定参数数组,可以是Array实例,也可以是arguments对象。
.call()方法与.apply()方法相似,不同之处在于,传递给函数的参数必须逐个列举出来。

两个方法的强大之处在于能够扩充函数赖以运行的作用域,并且对象不需要与方法有任何耦合关系。

.bind()创建一个函数的实例,其this值会被绑定到传给bind()函数的值。

window.color = "red";
var o = {color:"blue"};

function sayColor(){
    return this.color;
}

var objectSayColor = sayColor.bind(o);
objectSayColor();

.toLocaleString()、.toString()方法和.valueOf()方法始终都返回函数的代码。

5.6 基本包装类型

ES提供了三个特殊的引用类型:Boolean、Number和String。
每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让程序员能够调用一些方法来操作这些数据。

var s1 = "some text";
var s2 = s1.substring(2);
//当第二行代码访问s1时,访问过程处于一种读取模式,也就是从内存中读取这个字符串的值。
//在这个过程中,后台自动完成以下处理:创建String类型的一个实例,在实例上调用指定的方法,销毁这个实例。

注意:对基本包装类型的实例调用typeof会返回“object”,而且所有的基本包装类型的对象都会被转换为布尔值true。
也就是说:

var value = "25";
var number = Number(value);//转型函数(不推荐)
alert(typeof number);//"number"
var obj = new Number(value);//构造函数
alert(typeof obj);//"object"

Boolean类型
永远不建议使用Boolean对象,因为在使用typeof和instanceof操作符测试基本类型数值与引用类型数值时,得到的结果完全不同。
注意:var f = false;在逻辑操作中被认为是假,而var f = new Boolean(false);在逻辑操作中被认为是真。

Number类型
.toFixed()
按照指定的小数位返回数值的字符串表示,接收一个参数,指定输出结果中的小数位数。

.toExponential()
返回以指数表示法表示的数值的字符串形式,接收一个参数,指定输出结果中的小数位数。

.toPrecision()
得到表示某个数值的最合适的格式,可能是fixed格式,也可能是指数格式,接收一个参数,指定输出结果中所有数字的位数(不包括指数部分)

不建议直接实例化Number类型,原因同Boolean类型。

String类型
注意:即使字符串中包含双字节字符(不是占一个字节的ASCII字符),每个字符也仍然算一个字符。

.charAt()、.charCodeAt()
前者以单字符字符串形式返回给定位置的那个字符。
后者则是返回那个字符的编码。
可以使用[index]访问字符串中的特定字符。

.concat()
将一或多个字符串拼接起来,返回拼接得等的新字符,可接受任意多个参数。实践中更多的还是使用“+”操作。

.slice()、.substr()、.substring()
返回被操作字符串的一个子字符串。
第一个参数指定子字符串开始的位置。
第二个参数对于slice和substring指定的是子字符串最后一个字符后面的位置,而对于substr指定的是子字符串的长度。
在参数是负值的情况下,slice会将负值与字符串长度相加,substr会将负的第一个参数与字符串长度相加,负的第二个参数转换为0,substring会将所有的负参数转换为0(substring还有一个特性,它会将两个参数中较小的那个数作为开始位置)。

.indexOf()、.lastIndexOf()
从一个字符串中搜索给定的子字符串,然后返回子字符串的位置(没找到则返回-1)
可接收可选的第二个参数,表示从字符串中的哪个位置开始搜索。
前者向后搜索,后者向前搜索。

.trim()
创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果。

.toLowerCase()、.toLocaleLowerCase()、.toUpperCase()、.toLoacaleUpperCase()
字符串的大小写转换方法。

.match()
字符串中进行匹配,本质与调用RegExp的exec()方法相同。只接受一个参数,正则表达式或者RegExp对象。

.search()
字符串中进行匹配,只接受一个参数,正则表达式或者RegExp对象。返回第一个匹配项的索引,如果没有返回-1。

.replace()
替换子字符串,第一个参数是一个RegExp对象或一个字符串(这个字符串不会被转换为正则表达式),第二个参数是一个字符串或者一个函数。
如果第一个参数是字符串,那么只会替换第一个子字符串。
如果第二个参数是字符串,那么可以使用一些特殊的字符序列,将正则表达式操作得到的值插入到结果字符串中。

var text ="cat,bat,sat,fat";
result = text.replace(/(.at)/g,"word ($1)");
alert(result);//word(cat),word(bat),word(sat),word(fat)

如果第二个参数是一个函数,则对匹配项执行这个函数,进行更精细的操作,将函数的返回值作为替换的子字符串。
通常会向这个函数传递三个参数:模式的匹配项,模式匹配项在字符串中的位置和原始字符串。若正则表达式中定义了多个捕获组,则传递给函数的参数依次是模式匹配项、第一个捕获组的匹配项……最后一个捕获组的匹配项、模式匹配项在字符串中的位置和原始字符串。

.localeCompare()
比较两个字符串,如果在字母表中,字符串排在参数字符串之前,返回一个负数(多为-1);如果等于,则返回;如果在之后,返回一个正数(多为1)

String.fromCharCode()
静态方法。接收一或多个字符编码(数字而不是字符串),将它们转换为一个字符串。

5.7 单体内置对象

ES对内置对象的定义是:“由ES实现提供的、不依赖于宿主环境的对象,这些对象在ES程序执行之前就已经存在了。”
eg:Object、Array、String、Global、Math

Global对象
在ES中没有全局变量或全局函数;所有在全局作用域中定义的属性和函数,都是Global对象的属性。

encodeURI()、encodeURIComponent()
前者主要用于整个URL编码,后者则是用于URL中的某一段。
前者不会对本身属于URL的特殊字符进行编码,后者则会对它发现的任何非字母数字字符进行编码。

decodeURI()、decodeURIComponent()
与上一一对应。

eval()
就像一个完整的ES解析器,接收一个参数,即要执行的ES或JS字符串。被执行的代码具有与该执行环境相同的作用域链。

window对象
ES没有指出如何直接访问Globe对象,但Web浏览器都是将这个全局对象作为window对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,都成为了window对象的属性。
另一种取得Global对象的方法如下:

var global = function(){
    return this;
}();

Math对象
Math对象包含的属性大都是数学计算中会用到的一些特殊值。

Math.min()、Math.max()
从传入参数中返回最小值或最大值。
要找出数组中的最大值或最小值:

Math.max.apply(Math,数组);

Math.ceil()、Math.round()、Math.floor()
四舍五入的方法

Math.random()
返回0~1之间的一个随机数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《JavaScript高级程序设计》第4版是一本深入讲解JavaScript编程语言的书籍。该书详细介绍了JavaScript的基础知识、语法、面向对象编程、DOM操作、事件处理、Ajax、JSON等方面的内容。此外,该书还介绍了一些高级技术,如模块化编程、正则表达式、Web Workers、Web Storage等。该书适合有一定JavaScript基础的读者阅读,可以帮助读者深入了解JavaScript编程语言,提高编程技能。 ### 回答2: 《JavaScript高级程序设计》第4版(以下简称《JS高级程序设计》)是由李炎恢编写的一部JavaScript语言的经典教材,它被誉为“JavaScript圣经”。本书全面深入地讲解了JavaScript语言的核心概念、高级特性和最佳实践,对于想要深入学习JavaScript的开发者来说是一本必读之作。 首先,本书从JavaScript的基础知识开始,包括JavaScript的数据类型、变量、运算符、函数等。随后,本书详细介绍了JavaScript的面向对象编程,包括对象、原型、继承等概念,以及使用构造函数和类来创建对象的方法。 其次,本书不仅讲述了JavaScript的基本语法,更详细深入地介绍了诸如函数表达式、闭包、高阶函数、递归等高级特性,对于想要提高自己的JavaScript编程能力的开发者很有帮助。 最后,本书也介绍了一些实际的开发技巧和最佳实践,例如DOM操作、事件处理、Ajax、JSON、模块化开发等,让开发者在实际的开发中更加得心应手。 总之,《JavaScript高级程序设计》第4版是一本权威性的JavaScript经典教材,它涵盖了JavaScript的核心概念、高级特性和最佳实践,对于想要深入了解JavaScript的开发者来说是一本必读之作。无论是初学者还是有经验的开发者,都可以从中找到大量有用的知识和实践经验。 ### 回答3: 《JavaScript高级程序设计》第4版是由三位著的前端开发专家编写的JavaScript权威教程。本书介绍了JavaScript的核心概念、语言特性和应用方法,以及一些高级技巧和最佳实践。 本书的第一部分从JavaScript基础语法开始介绍,包括变量声明、数据类型、操作符、语句和函数等方面。第二部分主要介绍JavaScript的面向对象编程,包括原型链、继承和封装等概念。第三部分主要介绍JavaScript的一些高级特性,包括闭包、异步编程、事件和延迟加载等内容。第四部分主要介绍了如何使用JavaScript实现一些实际应用,包括调试、性能优化、动态Web页面和跨域请求等方面。 本书内容全面、深入,不仅介绍了JavaScript的基础知识,更重要的是让读者理解了JavaScript的思想和编程风格。编写本书的三位专家都是行业内的大牛,他们的经验和见解非常宝贵,能够帮助读者更好地理解JavaScript。同时,本书的配套网站还提供了很多实例代码和练习题,读者可以通过这些实践来深入理解JavaScript。 总之,《JavaScript高级程序设计》第4版是一本非常不错的JavaScript权威教程,无论是初学者还是专业开发者都可以从中受益匪浅。如果你想深入学习JavaScript,这本书绝对值得一读。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值