(二)JavaScript基础-基础概念(Object;函数;变量、作用域和内存问题;)

1.说明

在这里插入图片描述

       本文内容主要基于《JavaScript高级程序设计》(第3版),该书也断续的看过一遍,为便于进一步理解与基础知识的掌握,会增加一些个人的理解。
       由于该书出版时间为2012年,在2011年底ECMAScript第三版是大部分浏览器实现的一个版本,该书内容主要基于第三版定义的 ECMAScript 介绍这门语言的基本概念,并就第 5 版的变化给出说明。

2.语法

2.1 Object类型

1.ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段(Undefined、Null、Boolean、 Number 和String),而引用类型值指那些可能由多个值构成的对象(Object)
2. ECMAScript 中的对象其实就是一组属性与方法的集合,对象可以通过执行 new 操作符后跟要创建的对象类型的名称来创建。而创建 Object类型的实例并为其添加属性和(或)方法,就可以创建自定义对象。

var o = new Object();
var o = new Object; //不传参的时候可以这么创建,不推荐

Object 类型所具有的任何属性和方法也同样存在于创建的实例中。
Object 的每个实例都具有下列属性和方法。

1)constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数( constructor)就是 Object();
2)hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性(propertyName)必须以字符串形式指定(例 如:o . hasOwnProperty (“name”));
3)isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型;
4)propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句;与 hasOwnProperty()方法一样,作为参数的属性名必须以字符 串形式指定。
5) toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
6)toString():返回对象的字符串表示。
7)valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值 相同。

2.2 函数

函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行。 ECMA Script 中的函数使用 function 关键字来声明,后跟一组参数以及函数体。函数的基本语法如下所示:

function functionName(arg0, arg1,...,argN) {
statements
}
以下是一个函数示例:
function sayHi(name, message) {
alert("Hello " + name + "," + message);
}

ECMAScript 中的函数在定义时不必指定是否返回值。实际上,任何函数在任何时候都可以通过return 语句后跟要返回的值来实现返回值。

function sum(num1, num2) {
return num1 + num2;
}

严格模式对函数有一些限制:
1.不能把函数命名为 eval 或 arguments;
2.不能把参数命名为 eval 或arguments;
3.不能出现两个命名参数同名的情况。 如果发生以上情况,就会导致语法错误,代码无法执行。

2.2.1 参数

1.ECMAScript 函数的参数与大多数其他语言中函数的参数有所不同。 函数即使只定义一个参数,ECMAScript函数可以传递一个、三个甚至不传递参数。在函数体内可以通过 arguments 对象来访问这个参数数组,从而获取传递给函数的每一个参数。
2.通过访问 arguments 对象的 length 属性可以获知有多少个参数传递给了函数。

function sayHi() {
alert("Hello " + arguments[0] + "," + arguments[1]);
}

3.ECMAScript 的重载实现。

function doAdd() {
  if(arguments.length == 1) {
    alert(arguments[0] + 10);
  } else if (arguments.length == 2) {
    alert(arguments[0] + arguments[1]);
  }
}

4.arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。
5.arguments值永远与对应命名参数的值保持同步。

function doAdd(num1, num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}//doAdd(0,0)   返回10

注意:
1:num2 与arguments[1]内存空间是独立的,但它们的值会同步;
2:如果只传入了一个参数,那么为 arguments[1]设置的值不会反应到命名参数中。这是因为 arguments 对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。
3:ECMAScript 中的所有参数传递的都是值,不可能通过引用传递参数。

2.2.2 没有重载

ECMAScript 函数不能像传统意义上那样实现重载,如果在 ECMA Script 中定义了两个名字相同的函数,则该名字只属于后定义的函数。

2.3 变量、作用域和内存问题

1.ECMAScript 变量可能包含两种不同数据类型的值:基本类型值和引用类型值。 基本类型值指的是简单的数据段(Undefined、Null、Boolean、 Number 和 String),而引用类型值指那些可能由多个值构成的对象(Object);
2.基本数据类型是按值访问,引用类型的值是按引用访问的;
3.在很多语言中,字符串以对象的形式来表示,因此被认为是引用类型的,ECMAScript 放弃了这一传统。

2.3.1 变量

1.复制变量值
num1 中保存的值是 5。当使用 num1 的值来初始化 num2 时, num2 中也保存了值 5。但 num2中的 5 与 num1 中的 5 是完全独立的,该值只是 num1 中 5 的一个副本。此后,这两个变量可以参与任何操作而不会相互影响。

var num1 = 5;
var num2 = num1;

在这里插入图片描述
从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量。

var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"

在这里插入图片描述
2. 传递参数
ECMAScript 中所有函数的参数都是按值传递的。

基本类型
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,没有变化
alert(result); //30
引用类型
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

如何证明引用类型按值传递

function setName(obj) {//一定要理解为什么是按值传递。
obj.name = "Nicholas";//1.反证明思想  如果按引用那么值会改变
obj = new Object();//2.这里的按值传递另一层含义
obj.name = "Greg";//就是内部引用(局部对象)与外部引用关系
}
var person = new Object();
setName(person);
alert(person.name); //"Nicholas"

2.3.2 作用域

1.作用域(执行环境)全局执行环境是最外围的一个执行环境。根据 ECMAScript 实现所在的宿主环境不同,表示执行环境的对象也不一样。在Web 浏览器中,全局执行环境被认为是 window 对象,因此所有全局变量和函数都是作为 window对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或浏览器——时才会被销毁)。
2.每个函数都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。ECMAScript程序中的执行流正是由这个方便的机制控制着。

var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 这里可以访问 color、 anotherColor 和 tempColor
}
// 这里可以访问 color 和 anotherColor,但不能访问 tempColor
swapColors();
}
// 这里只能访问 color
changeColor();

在这里插入图片描述
1.延长作用域链
虽然执行环境的类型总共只有两种——全局和局部(函数),但还是有其他办法来延长作用域链。具体来说,就是当执行流进入下列任何一个语句时,作用域链就会得到加长:

1.try-catch 语句的 catch 块;
2.with 语句。

with 语句接收的是 location 对象,因此其变量对象中就包含了 location 对象的所有属性和方法。

function buildUrl() {
var qs = "?debug=true";
with(location){
var url = href + qs;
}
return url;
}

2.没有块级作用域
1.JavaScript 没有块级作用域,在其他类 C 的语言中,由花括号封闭的代码块都有自己的作用域(如果用 ECMAScript 的话来讲,就是它们自己的执行环境)。

for (var i=0; i < 10; i++){
doSomething(i);
}
alert(i); //10

2.声明变量:如果初始化变量时没有使用 var 声明,该变量会自动被添加到全局环境。
3. 查询标识符:当在某个环境中为了读取或写入而引用一个标识符时,必须通过搜索来确定该标识符实际代表什么。搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。如果在局部环境中找到了该标识符,搜索过程停止,变量就绪。如果在局部环境中没有找到该变量名,则继续沿作用域链向上搜索。搜索过程将一直追溯到全局环境的变量对象。如果在全局环境中也没有找到这个标识符,则意味着该变量尚未声明。

var color = "blue";
function getColor(){
return color;
}
alert(getColor()); //"blue"

在这里插入图片描述

2.3.3 内存问题(垃圾收集)

在编写 JavaScript 程序时,开发人员不用再关心内存使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理。这种垃圾收集机制的原理其实很简单:找出那些不再继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性地执行这一操作。
1.标记清除

1.JavaScript 中最常用的垃圾收集方式是标记清除( mark-and-sweep)。当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
2.到 2008 年为止, IE、 Firefox、 Opera、 Chrome 和 Safari 的JavaScript实现使用的都是标记清除式的垃圾收集策略(或类似的策略),只不过垃圾收集的时间间隔互有不同。

2.引用计数

1.另一种不太常见的垃圾收集策略叫做引用计数( reference counting)。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾收集器下次再运行时,它就会释放那些引用次数为零的值所占用的内存。
2.将变量设置为 null 意味着切断变量与它此前引用的值之间的连接。当垃圾收集器下次运行时,就 会删除这些值并回收它们占用的内存。

3.性能问题(触发垃圾回收机制)

1.各浏览器有自己触发垃圾回收的指标(机制);
2. 在有的浏览器中可以触发垃圾收集过程,但我们不建议读者这样做。在IE 中,调用 window.CollectGarbage()方法会立即执行垃圾收集。在 Opera 7 及更高版本中,调用 window.opera.collect()也会启动垃圾收集例程。

4.管理内存

1.确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为null来释放其引用——这个做法叫做解除引用( dereferencing)。
2.解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值