Javascript学习笔记

Links:
https://mp.weixin.qq.com/s/PRCTF5nk1613-Nhc2JY4dw

分布式十二问!

https://mp.weixin.qq.com/s/f_Q8V7TQaS4NDRPS0BNkkA

4 种 MySQL 同步 ES 方案

 

 

 

 

 

系统地回顾一下javascript。嗯。

主要参考:

  1. 微软JScript用户指南
  2. Professional JavaScript for Web Developers
  3. JavaScript The Definitive Guide, 5th Edition

JScript基础

JScript 的变量


表达式

3.9                       // 数字文字
"Hello!"                  // 字符串文字
false                     // 布尔文字
null                       // 文字空值
{x:1, y:2}             // 对象文字
[1,2,3]                  // 数组文字
function(x){return x*x;}  // 函数文字


变量声明

var count;  // 单个声明。
var count, amount, level;  // 用单个 var 关键字声明的多个声明。
var count = 0, amount = 100;  // 一条语句中的变量声明和初始化。

 

强制转换

JScript 是一种自由类型的语言。在 Jscript 中,可以对不同类型的值执行运算,不必担心 JScript 解释器产生异常。相反,JScript 解释器自动将数据类型之一改变(强制转换)为另一种数据类型,然后执行运算。例如:

 

运算结果
数值与字符串相加 将数值强制转换为字符串。
布尔值与字符串相加 将布尔值强制转换为字符串。
数值与布尔值相加 将布尔值强制转换为数值。

var x = 2000;      // 一个数字。
var y = "Hello";   // 一个字符串。
x = x + y;         // 将数字强制转换为字符串。
document.write(x); // 输出 2000Hello。

要想显式地将字符串转换为整数,使用 parseInt 方法。要想显式地将字符串转换为数字,使用 parseFloat 方法。请注意,比较大小时字符串自动转换为相等的数字,但加法(连接)运算时保留为字符串。


JScript 的数据类型


Jscript 有三种主要数据类型、两种复合数据类型和两种特殊数据类型。

主要(基本)数据类型是:

  • 字符串
  • 数值
  • 布尔

复合(引用)数据类型是:

  • 对象
  • 数组

特殊数据类型是:

  • Null
  • Undefined

 

浮点值 

JScript包含特殊值数字。它们是:

  • NaN (不是数)。当对不适当的数据进行数学运算时使用,例如字符串或未定义值。
  • 正无穷大。在JScript中如果一个正数太大的话使用它来表示。
  • 负无穷大。在JScript中如果一个负数太大的话使用它来表示。
  • 正0和负0。Jscript区分正0和负0。 

Null 数据类型

在 Jscript 中数据类型 null 只有一个值:null。关键字 null 不能用作函数或变量的名称。

包含 null 的变量包含“无值”或“无对象”。换句话说,该变量没有保存有效的数、字符串、boolean、数组或对象。可以通过给一个变量赋 null 值来清除变量的内容。

请注意,在 Jscript 中,null 与 0 不相等(与在 C 和 C++ 中不同)。同时应该指出的是,Jscript中 typeof 运算符将报告 null 值为 Object 类型,而非类型 null。这点潜在的混淆是为了向下兼容。

Undefined 数据类型

如下情况使返回 undefined 值:

  • 对象属性不存在,
  • 声明了变量但从未赋值。

注意不能通过与 undefined 做比较来测试一个变量是否存在,虽然可以检查它的类型是否为“undefined”。在以下的代码范例中,假设程序员想测试是否已经声明变量 x :

// 这种方法不起作用
if (x == undefined)
// 作某些操作

// 这个方法同样不起作用- 必须检查
// 字符串 "undefined"
if (typeof(x) == undefined)
// 作某些操作

// 这个方法有效
if (typeof(x) == "undefined")
// 作某些操作

考虑将 undefined 值与null做比较。

someObject.prop == null;

如下情况时,比较的结果为 true

  • 如果属性 someObject.prop 包含 null 值,
  • 如果属性 someObject.prop 不存在。
  • 要检查一个对象属性是否存在,可以使用新的 in 运算符:
if ("prop" in someObject)
// someObject
有属性 'prop'

JScript 的运算符 


== (相等)与 === (严格相等)的区别在于恒等运算符在比较前强制转换不同类型的值。例如,恒等对字符串 "1" 与数值 1 的比较结果将为 true。而严格相等不强制转换不同类型的值,因此它认为字符串 "1" 与数值 1 不相同。

基本的字符串、数值和布尔值是按值比较的。如果它们的值相同,比较结果为相等。对象(包括ArrayFunctionStringNumberBooleanError、Date以及 RegExp 对象)按引用比较。即使这些类型的两个变量具有相同的值,只有在它们正好为同一对象时比较结果才为 true。

例如:

// 具有相同值的两个基本字符串。
var string1 = "Hello";
var string2 = "Hello";

// 具有相同值的两个 String 对象。
var StringObject1 = new String(string1);
var StringObject2 = new String(string2);

// 比较结果为 true
if (string1 == string2)
// 执行某些命令(将要运行的)。

// 比较结果为 false
if (StringObject1 == StringObject2)
//执行某些命令(不会运行)。

// 要比较 String 对象的值,
// toString() 或者 valueOf() 方法。
if (StringObject1.valueOf() == StringObject2)
//执行某些命令(将要运行的)。

控制程序的流程 


第一种是选择结构。用来指明两种程序流方向,在程序中创建一个交叉点(像岔路)。在 Jscript 中有四种选择结构可用。

  • 单一选择结构(if),
  • 二路选择结构(if/else),
  • 内联三元运算符 ?:
  • 多路选择结构(switch)。

第二种类型的程序控制结构是循环结构。使用循环结构来指明当某些条件保持为真时要重复的动作。当控制语句的条件得到满足时(通常在某些迭代的特定数字后),控制跳过循环结构传递到下条语句。在 Jscript 中有四种循环结构可用。

  • 在循环的开头测试表达式(while),
  • 在循环的末尾测试表达式(do/while),
  • 对对象的每个属性都进行操作(for/in),
  • 由计数器控制的循环(for)。

通过嵌套和堆栈选择、循环控制结构,可以创建相当复杂的脚本。

第三种形式的结构程序流由意外处理给出,本文档不作讨论。

使用 for...in 循环

JScript 提供了一种特别的循环方式来遍历一个对象的所有用户定义的属性或者一个数组的所有元素。for...in 循环中的循环计数器是一个字符串,而不是数字。它包含当前属性的名称或者当前数组元素的下标。

下面的代码范例应在 Internet 浏览器中运行,因为它使用 alert 方法,该方法不属于 Jscript。

// 创建具有某些属性的对象
var myObject = new Object();
myObject.name = "James";
myObject.age = "22";
myObject.phone = "555 1234";

// 枚举(循环)对象的所有属性
for (prop in myObject)
{
// 显示 "The property 'name' is James",等等。
window.alert("The property '" + prop + "' is " + myObject[prop]);
}

尽管 for...in 循环看起来像 VBScript 的 For Each...Next 循环,其实并不一样。JScript 的 for...in 循环重复Jscript 对象所有的属性。VBScript 的 For Each...Next 循环重复集合中的所有项目。要循环 JScript 中的所有集合,需要用 Enumerator 对象。尽管某些对象(像 Internet 浏览器中的那些)支持 VBScript 的 For Each...Next 和 Jscript 的 for...in 循环,但多数对象并不都支持。  

JScript 函数 


Microsoft Jscript 函数执行操作,也可以返回值。某些时候是计算或比较的结果。函数又被称为“全局方法”。 

 

JScript对象 


Jscript 对象是属性和方法的集合。一个方法就是一个函数,是对象的成员。属性是一个值或一组值(以数组或对象的形式),是对象的成员。Jscript 支持四种类型的对象:内部对象、生成的对象、宿主给出的对象(如 Internet 浏览器中的 windowdocument)以及 ActiveX 对象(外部组件)。

作为数组的对象

在 Jscript 中,对象和数组几乎是以相同的方式处理的。对象和数组均可以被赋予任意值,实际上数组只是一种特殊的对象。数组和对象的区别在于数组有一个“奇妙的” length 属性,而对象没有。这意味着可以给数组的一个元素赋予比其他元素更大的值。例如,myArray[100] = "hello" — 然后 length 属性将自动地被更新为 101(新长度)。同样,如果修改数组的 length 属性,将删除不再是数组部分的元素。

Jscript 中所有的对象均支持“expando”属性或那些可以在运行时动态添加和删除的属性。这些属性可以有包含数字的任意名称。如果属性的名称是简单的标识符<<参考标识符规则>>,可以在对象名称的后面加句点,例如:

var myObj = new Object();

//
添加两个 expando 属性,'name' 'age'
myObj.name = "Fred";
myObj.age = 42;

如果属性名称不是一个简单的标识符,或者在写脚本的时候不知道,可以在方括号中使用任意表达式来索引属性。在 Jscript 中所有 expando 属性的名称在被添加到对象之前被转换为字符串。

var myObj = new Object();

//
添加两个无法写在 object.property
// 法中的 expando 属性。
// 第一个属性包含无效字符(空格),
// 所以必须写在方括号里。
myObj["not a valid identifier"] = "This is the property value";

// 第二个 expando 名称是一个数字,
// 所以也必须写在方括号里。
myObj[100] = "100";

传统的作法是赋给数组元素以 0 开始的数字索引。这些数组元素与 length 属性相交互。然而,由于所有的数组也是对象,也支持 expando 属性。请注意,虽然如此,expando 属性并不以任何方式与 length 属性相交互。例如:

// 三个元素的数组
var myArray = new Array(3);

// 添加数据
myArray[0] = "Hello";
myArray[1] = 42;
myArray[2] = new Date(2000, 1, 1);

// 显示数组的长度 3
window.alert(myArray.length);

// 添加某些 expando 属性
myArray.expando = "JScript!";
myArray["another Expando"] = "Windows";

// 仍然显示 3,因为两个 expando 属性
// 并不影响长度。
window.alert(myArray.length);

虽然 Jscript 并不直接支持多维数组,但是可以在数组元素中存储任意种类的数据 — 包含其他数组。所以通过在另一个数组的元素里存储其他数组可以得到多维数组的特性。例如,下面的代码为最大为 5 的数字建立了乘法表:

// 若是更大的表请改变本数
var iMaxNum = 5;
// 循环计数
var i, j;

// 新数组。由于数组从 0 开始计数,
// 而不是 1,所以数组大小为 iMaxNum + 1
var MultiplicationTable = new Array(iMaxNum + 1);

// 为每个主要的数做循环(表中的每一行)
for (i = 1; i <= iMaxNum; i++)
{
// 生成表中的列
MultiplicationTable[i] = new Array(iMaxNum + 1);

// 将乘法的结果存在行中
for (j = 1; j <= iMaxNum; j++)
{
MultiplicationTable[i][j] = i * j;
}
}

window.alert(MultiplicationTable[3][4]); // 显示 12
window.alert(MultiplicationTable[5][2]); // 显示 10
window.alert(MultiplicationTable[1][4]); // 显示 4 

创建自己的对象


要创建自己的对象实例,必须首先为其定义一个构造函数。构造函数创建一个新对象,赋予对象属性,并在合适的时候赋予方法。例如,下面的示例为 pasta 对象定义了构造函数。注意 this 关键字的使用,它指向当前对象。

// pasta 是有四个参数的构造器。
function pasta(grain, width, shape, hasEgg)
{
// 是用什么粮食做的?
this.grain = grain;

// 多宽?(数值)
this.width = width;

// 横截面形状?(字符串)
this.shape = shape;

// 是否加蛋黄?(boolean
this.hasEgg = hasEgg;
}

定义了对象构造器后,用 new 运算符创建对象实例。

var spaghetti = new pasta("wheat", 0.2, "circle", true);
var linguine = new pasta("wheat", 0.3, "oval", true);

可以给对象实例添加属性以改变该实例,但是用相同的构造器生成的其他对象定义中并不包括这些属性,而且除非你特意添加这些属性那么在其他实例中并不显示出来。如果要将对象所有实例的附加属性显示出来,必须将它们添加到构造函数或构造器原型对象(原型在高级文档中讨论)中。

// spaghetti 的附加属性。
spaghetti.color = "pale straw";
spaghetti.drycook = 7;
spaghetti.freshcook = 0.5;

var chowFun = new pasta("rice", 3, "flat", false);
// chowFun 对象或其他现有的 pasta 对象
// 都没有添加到 spaghetti 对象
// 的三个新属性。


// 将属性‘foodgroup’加到 pasta 原型对象
// 中,这样 pasta 对象的所有实例都可以有该属性,
// 包括那些已经生成的实例。
pasta.prototype.foodgroup = "carbohydrates"

// 现在 spaghetti.foodgroupchowFun.foodgroup,等等
// 均包含值“carbohydrates”。

在定义中包含方法

可以在对象的定义中包含方法(函数)。一种方法是在引用别处定义的函数的构造函数中添加一个属性。例如,下面的示例扩充上面定义的 pasta 构造函数以包含 toString 方法,该方法将在显示对象的值时被调用。

// pasta 是有四个参数的构造器。
// 第一部分与上面相同。
function pasta(grain, width, shape, hasEgg)
{
// 用什么粮食做的?
this.grain = grain;

// 多宽?(数值)
this.width = width;

// 横截面形状?(字符串)
this.shape = shape;

// 是否加蛋黄?(boolean
this.hasEgg = hasEgg;

// 这里添加 toString 方法(如下定义)。
// 注意在函数的名称后没有加圆括号;
// 这不是一个函数调用,而是
// 对函数自身的引用。
this.toString = pastaToString;
}

// 实际的用来显示 past 对象内容的函数。
function pastaToString()
{
// 返回对象的属性。

return "Grain: " + this.grain + "\n" +
"Width: " + this.width + "\n" +
"Shape: " + this.shape + "\n" +

"Egg?: " + Boolean(this.hasEgg);
}

var spaghetti = new pasta("wheat", 0.2, "circle", true);
// 将调用 toString() 并显示 spaghetti 对象
// 的属性(需要Internet 浏览器)。
window.alert(spaghetti);

内部对象


Microsoft Jscript 提供了 11 个内部(或“内置”)对象。它们是ArrayBooleanDateFunctionGlobalMathNumberObjectRegExpError 以及 String 对象。每一个对象有相关的方法和属性,这在语言参考中有详细的描述。本节中也描述了某些对象。

Array 对象

数组下标可以被认为是对象的属性,它是通过数字索引来引用的。注意添加到数组中的已命名的属性不能通过数字来索引;它们是与数组元素分离的。

使用 new 运算符和 Array() 构造器 生成一个新的数组,如下面的示例。

var theMonths = new Array(12);
theMonths[0] = "Jan";
theMonths[1] = "Feb";
theMonths[2] = "Mar";
theMonths[3] = "Apr";
theMonths[4] = "May";
theMonths[5] = "Jun";
theMonths[6] = "Jul";
theMonths[7] = "Aug";
theMonths[8] = "Sep";
theMonths[9] = "Oct";
theMonths[10] = "Nov";
theMonths[11] = "Dec";

用关键字 Array 生成数组时,Jscript 包含了 length 属性,该属性记录了数组入口数。如果没有给该属性指定值,则设置长度为 0 且数组没有入口点。如果指定一个数值,则将长度设置为该数。如果指定了不止一个参数,则这些参数被用作数组的入口。另外,参数的数目被赋给 length 属性。如下面的示例与前一个示例是等价的。

var theMonths = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", 
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec");

当向用关键字 Array 生成的数组中添加元素时,Jscript 自动改变属性 length 的值。Jscript 中的数组索引总是以 0 开始,而不是 1,所以属性 length 通常比数组的最大索引大 1。

String对象

在 Jscript 中,可以将字符串(和数)当作对象来处理。string 对象 有一些内置方法,可以和自己的字符串一起使用。其中一个是substring 方法,它返回字符串的一部分。该方法以两个数字作为参数。

aString = "0123456789";
var aChunk = aString.substring(4, 7); //
aChunk 设为 "456"
var aNotherChunk = aString.substring(7, 4); // aNotherChunk 设为 "456"
// 使用上面生成数组的示例:
firstLetter = theMonths[5].substring(0,1); // 将变量 firstLetter 设为“J”。

String 对象的另一个属性是 length 属性。本属性包含了字符串中的字符数(空字符串为 0)。它是一个数值,可以直接在计算中使用。

var howLong = "Hello World".length  // 设置变量 howLong  11

Math 对象

Math 对象有许多预定义属性和方法。属性是特殊的数字。这些特殊的数字之一是 pi 值(近似 3.14159…)。这是 Math.PI 属性,如下例所示。

// 声明一个半径变量并赋数值。
var circleArea = Math.PI * radius * radius; // 注意 Math PI 大写。

Math 对象的一个内置方法是乘幂方法(或 pow),使用该方法求得指定数的幂次。下面的例子同时使用了 pi 和乘幂。

// 本公式计算给定半径的球体的体积。
volume = (4/3)*(Math.PI*Math.pow(radius,3));

Date 对象

Date 对象可以被用来表示任意的日期和时间,获取当前系统日期以及计算两个日期的间隔。它拥有一些预定义的属性和方法。通常,Date 对象给出星期;月份,天数和年份;以及以小时,分钟和秒表示的时间。该信息是基于 1970 年1 月 1 日 00:00:00.000 GMT 开始的毫秒数,其中 GMT 是格林威治标准时间(首选术语是 UTC,或者“全球标准时间”,它引用的信号是由“世界时间标准”发布的)。Jscript 可以处理 250,000 B.C. 到 255,000 A.D范围内的日期。

使用 new 运算符创建一个新的 Date 对象。下面的示例计算当年已过去的天数和今年剩下的天数。

/*
本示例使用前面定义的月份名称数组。
第一条语句以“Day Month Date 00:00:00 Year”格式
thisIsToday 变量赋值。
*/
var thisIsToday = new Date();

var toDay = new Date(); //获取今天的日期。

// 提取年,月,日。
var thisYear = toDay.getFullYear();
var thisMonth = theMonths[toDay.getMonth()];
var thisDay = thisMonth + " " + toDay.getDate() + ", " + thisYear;

Number 对象

除了 Math 对象中可用的特殊数值属性(例如 PI)外,在 Microsoft Jscript 中, Number 对象有几个其他的数值属性。

属性描述
MAX_VALUE 可能的最大数大约为 1.79E+308;可以是正数或负数。(具体数值随系统不同而有微小差别。)
MIN_VALUE 可能的最小数大约为 2.22E-308;可以是正数或负数。(具体数值随系统不同而有微小差别。)
NaN 特殊非数量值,“不是数值”。
POSITIVE_INFINITY 比最大正数(Number.MAX_VALUE)还要大的任意正值自动被转换为此值,代表正无穷大。
NEGATIVE_INFINITY 比最小的负数(负的 Number.MAX_VALUE)还小的任意值被自动转换为此值,代表负无穷。

 

Number.NaN 是一个特殊的属性,被定义为“不是数值”。例如被 0 除返回 NaN。试图解析一个无法被解析为数字的字符串同样返回 Number.NaN。把 NaN 与任何数值或本身作比较的结果都是不相等。不能通过与 Number.NaN 比较来测试 NaN 结果,而应该使用 isNaN() 函数。 

高级 JScript 

创建高级对象 


使用构造函数来创建对象

构造函数是一个函数,调用它来例示并初始化特殊类型的对象。可以使用 new 关键字来调用一个构造函数。下面给出了使用构造函数的新示例。

var myObject = new Object();             // 创建没有属性的通用对象。
var myBirthday = new Date(1961, 5, 10); // 创建一个 Date 对象。
var myCar = new Car(); // 创建一个用户定义的对象,并初始化其属性。

通过构造函数将一个参数作为特定的 this 关键字的值传递给新创建的空对象。然后构造函数负责为新对象执行适应的初始化(创建属性并给出其初始值)。完成后,构造函数返回它所构造的对象的一个参数。

编写构造函数

可以使用 new 运算符结合像 Object()Date()Function() 这样的预定义的构造函数来创建对象并对其初始化。面向对象的编程其强有力的特征是定义自定义构造函数以创建脚本中使用的自定义对象的能力。创建了自定义的构造函数,这样就可以创建具有已定义属性的对象。下面是自定义函数的示例(注意 this 关键字的使用)。

function Circle (xPoint, yPoint, radius) {
this.x = xPoint; //
圆心的 x 坐标。
this.y = yPoint; // 圆心的 y 坐标。
this.r = radius; // 圆的半径。
}

调用 Circle 构造函数时,给出圆心点的值和圆的半径(所有这些元素是完全定义一个独特的圆对象所必需的)。结束时 Circle 对象包含三个属性。下面是如何例示 Circle 对象。

var aCircle = new Circle(5, 11, 99);

使用原型来创建对象

在编写构造函数时,可以使用原型对象(它本身是所有构造函数的一个属性)的属性来创建继承属性和共享方法。原型属性和方法将按引用复制给类中的每个对象,因此它们都具有相同的值。可以在一个对象中更改原型属性的值,新的值将覆盖默认值,但仅在该实例中有效。属于这个类的其他对象不受此更改的影响。下面给出了使用自定义构造函数的示例,Circle(注意 this 关键字的使用)。

Circle.prototype.pi = Math.PI;
function ACirclesArea () {
return this.pi * this.r * this.r; //
计算圆面积的公式为 ?r2
}
Circle.prototype.area = ACirclesArea; // 计算圆面积的函数现在是 Circle Prototype 对象的一个方法。
var a = ACircle.area(); // 此为如何在 Circle 对象上调用面积函数。

使用这个原则,可以给预定义的构造函数(都具有原型对象)定义附加属性。例如,如果想要能够删除字符串的前后空格(与 VBScript 的 Trim 函数类似),就可以给 String 原型对象创建自己的方法。

// 增加一个名为 trim 的函数作为
// String 构造函数的原型对象的一个方法。
String.prototype.trim = function()
{
// 用正则表达式将前后空格
// 用空字符串替代。
return this.replace(/(^\s*)|(\s*$)/g, "");
}

// 有空格的字符串
var s = " leading and trailing spaces ";

// 显示 " leading and trailing spaces (35)"
window.alert(s + " (" + s.length + ")");

// 删除前后空格
s = s.trim();
// 显示"leading and trailing spaces (27)"
window.alert(s + " (" + s.length + ")");

变量范围


JScript 有两种变量范围:全局和局部。如果在任何函数定义之外声明了一个变量,则该变量为全局变量,且该变量的值在整个持续范围内都可以访问和修改。如果在函数定义内声明了一个变量,则该变量为局部变量。每次执行该函数时都会创建和破坏该变量;且它不能被该函数外的任何事物访问。

像 C++ 这样的语言也有“块范围”。在这里,任何一对“{}”都定义新的范围。JScript 不支持块范围。

一个局部变量的名称可以与某个全局变量的名称相同,但这是完全不同和独立的两个变量。因此,更改一个变量的值不会影响另一个变量的值。在声明局部变量的函数内,只有该局部变量有意义。

var aCentaur = "a horse with rider,";  // aCentaur 的全局定义。

// JScript 代码,为简洁起见有省略。
function antiquities() // 在这个函数中声明了一个局部 aCentaur 变量。
{

// JScript 代码,为简洁起见有省略。
var aCentaur = "A centaur is probably a mounted Scythian warrior";

// JScript 代码,为简洁起见有省略。
   aCentaur += ", misreported; that is, "; // 添加到局部变量。

// JScript 代码,为简洁起见有省略。
} // 函数结束。

var nothinginparticular = antiquities();
aCentaur += " as seen from a distance by a naive innocent.";

/*
在函数内,该变量的值为 "A centaur is probably a mounted Scythian warrior,
misreported; that is, ";在函数外,该变量的值为这句话的其余部分:
"a horse with rider, as seen from a distance by a naive innocent."
*/

很重要的一点是注意变量是否是在其所属范围的开始处声明的。有时这会导致意想不到的情况。

tweak();
var aNumber = 100;
function tweak() {
var newThing = 0; //
显式声明 newThing 变量。

// 本语句将未定义的变量赋给 newThing,因为已有名为 aNumber 的局部变量。
newThing = aNumber;

//下一条语句将值 42 赋给局部的 aNumberaNumber = 42;
if (false) {
var aNumber; // 该语句永远不会执行。
aNumber = 123; // 该语句永远不会执行。
} // 条件语句结束。

} // 该函数定义结束。

当 JScript 运行函数时,首先查找所有的变量声明,

var someVariable;

并以未定义的初始值创建变量。如果变量被声明时有值,

var someVariable = "something";

那么该变量仍以未定义的值初始化,并且只有在运行了声明行时才被声明值取代,假如曾经被声明过。

JScript 在运行代码前处理变量声明,所以声明是位于一个条件块中还是其他某些结构中无关紧要。JScript 找到所有的变量后立即运行函数中的代码。如果变量是在函数中显式声明的 — 也就是说,如果它出现于赋值表达式的左边但没有用 var 声明 — 那么将把它创建为全局变量。 

 

复制、传递和比较数据


在 JScript 中,对数据的处理取决于该数据的类型。

按值和按引用的比较

Numbers 和 Boolean 类型的值 (truefalse) 是按值来复制、传递和比较的。当按值复制或传递时,将在计算机内存中分配一块空间并将原值复制到其中。然后,即使更改原来的值,也不会影响所复制的值(反过来也一样),因为这两个值是独立的实体。

对象、数组以及函数是按引用来复制、传递和比较的。 当按地址复制或传递时,实际是创建一个指向原始项的指针,然后就像拷贝一样来使用该指针。如果随后更改原始项,则将同时更改原始项和复制项(反过来也一样)。实际上只有一个实体;“复本”并不是一个真正的复本,而只是该数据的又一个引用。

当按引用比较时,要想比较成功,两个变量必须参照完全相同的实体。例如,两个不同的 Array 对象即使包含相同的元素也将比较为不相等。要想比较成功,其中一个变量必须为另一个的参考。要想检查两个数组是否包含了相同的元素,比较 toString() 方法的结果。

最后,字符串是按引用复制和传递的,但是是按值来比较的。请注意,假如有两个 String 对象(用 new String("something") 创建的),按引用比较它们,但是,如果其中一个或者两者都是字符串值的话,按值比较它们。

注意   鉴于 ASCII和 ANSI 字符集的构造方法,按序列顺序大写字母位于小写字母的前面。例如 "Zoo" 小于 "aardvark"。如果想执行不区分大小写的匹配,可以对两个字符串调用 toUpperCase()toLowerCase()

传递参数给函数

按值传递一个参数给函数就是制作该参数的一个独立复本,即一个只存在于该函数内的复本。即使按引用传递对象和数组时,如果直接在函数中用新值覆盖原先的值,在函数外并不反映新值。只有在对象的属性或者数组的元素改变时,在函数外才可以看出。

例如(使用 IE 对象模式):

// 本代码段破坏(覆盖)其参数,所以
// 调用代码中反映不出变化。
function Clobber(param)
{
// 破坏参数;在调用代码中
// 看不到。
param = new Object();
param.message = "This will not work";
}

// 本段代码改变参数的属性,
// 在调用代码中可看到属性改变。
function Update(param)
{
// 改变对象的属性;
// 可从调用代码中看到改变。
param.message = "I was changed";
}

// 创建一个对象,并赋给一个属性。
var obj = new Object();
obj.message = "This is the original";

// 调用 Clobber,并输出 obj.message。注意,它没有发生变化。
Clobber(obj);
window.alert(obj.message); // 仍然显示 "This is the original"

// 调用 Update,并输出 obj.message。注意,它已经被改变了。
Update(obj);
window.alert(obj.message); // 显示 "I was changed"

检验数据

当按值进行检验时,是比较两个截然不同的项以查看它们是否相等。通常,该比较是逐字节进行的。当按引用进行检验时,是看这两项是否是指向同一个原始项的指针。如果是,则比较结果是相等;如果不是,即使它们每个字节都包含完全一样的值,比较结果也为不相等。

按引用复制和传递字符串能节约内存;但是由于在字符串被创建后不能进行更改,因此可以按值进行比较。这样可以检查两个字符串是否包含相同的内容,即使它们是完全独立产生的。 

 

使用数组


数组下标

JScript 中的数组是稀疏的。也就是说,如果一个数组具有三个元素,编号分别为 0、1 和 2,您就可以创建元素 50,而不必担心从 3 到 49 的参数。如果该数组有一个自动的 length 变量,(请参阅内部对象了解有关数组长度的自动监控的说明),该 length 变量被设为 51,而不是 4。当然您可以创建各元素的编号之间没有间隙的数组,不过没有必要这样做。

在 JScript 中,对象和数组几乎相同。两个主要差别是对象没有自动长度属性,而数组没有对象的属性和方法。

数组寻址

使用方括号“[]”来寻址数组。方括号中是一个数值或一个值为整数的表达式。下面的示例假定在脚本的其他地方已定义了entryNum 变量,且已赋值。

theListing = addressBook[entryNum];
theFirstLine = theListing[1];

将对象作为关联数组

通常,使用点运算符“.”访问对象的属性。例如,

myObject.aProperty

在这里,属性名称是一个标识符。也可以用索引运算符“[]”访问对象的属性。在这里,是把对象看作一个关联数组。关联数组是一种数据结构,它可以动态地将任意的数据的值与任意的字符串相关联。例如,

myObject["aProperty"] // 与上面相同。

尽管索引运算符更多地用于访问数组元素,当用于对象时,索引总是以字符串文字表示的属性名称。

注意访问对象属性的两种方法的重要差异。

运算符属性名称作为对属性名称的处理
点“.” 标识符 不能作为数据处理
索引“[]” 字符串文字 被作为数据处理

在运行之前并不知道属性名称时,这个差异会有用(比如基于用户输入构造对象时)。要想从一个关联数组提取所有的属性,必须用 for … in 循环。

脚本问题解答


如果不够细致,任何编程语言都有一些可能发生错误的地方,而且每种语言都有其特殊之处。例如,对于 null 值: JScript 中这个值与 C 或 C++ 语言中的 Null 值所起的作用是不一样的。

下面提供了一些在编写 JScript 脚本时可能遇到的问题。

脚本解释顺序

对 JScript 的解释是 Web 浏览器的 HTML 语法分析处理的一部分。因此,如果在文档的 <HEAD> 标识中放置了一个脚本,则将在检查所有的 <BODY> 标识之前加以解释。如果在 <BODY> 标识中将创建对象,但由于在分析处理 <HEAD> 标识时这些对象尚不存在,因而不能被脚本操作。

注意   本情况特定于 IE。ASP 和 WSH 具有不同的运行模式(其他宿主亦是)。

自动类型强制

JScript 是一种具有自动强制的自由类型语言。因此,尽管实际上不同类型的值是不相等的,但对下述示例中的表达式求值都将得到 true

"100" == 100;
false == 0;

要核对类型与值都一致,用“严格相等”运算符(===)。下面两个表达式的值为 false:

"100" === 100;
false === 0;

对对象使用 for...in 循环

当使用 for...in 循环对某个对象的属性进行遍历时,不必预先确定或管理将要指定给该循环计数器变量的对象字段的顺序。此外,在该语言的不同实现方案中该顺序可能会不一样。

with 关键字

with 语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性。要给对象创建新的属性,必须明确地引用该对象。

this 关键字

尽管可以在对象的定义范围内使用 this 关键字来引用该对象本身,但是当函数不是该对象的定义时,就不能象普通情况那样使用 this 或类似的关键字来引用当前的执行函数。如果该函数被指定为某个对象的方法,则可以在该函数内使用 this 关键字来引用该对象。

编写一个脚本,该脚本在 IE 中写脚本

当解释程序遇到</SCRIPT>标记时会终止当前脚本。要显示"</SCRIPT>" 本身,请将其改写为至少两个字符串,例如 "</SCR" 和 "IPT>",这样就可以在输出语句中将其连接在一起。

IE 中的隐式窗口引用

由于同时可以打开多个窗口,任何隐式的窗口引用都被指向当前窗口。对于其他窗口必须使用显式引用。

 

posted @ 2009-10-27 19:18  thxis0  阅读(153)  评论(0)    收藏  举报