0%

基本类型和引用类型的值

ECMAScript变量可能有两种数据类型的值,基本类型值和引用类型值,基本类型值 指的是简单的数据段,而引用类型值指的是那些可能有多个值构成的对象。

基本数据类型的值都按值访问的,我们可以直接对保存在变量中的值进行操作。而引用类型的值是保存在内存中的对象,JavaScript不允许我们直接对内存进行操作,操作对象的值实际上是通过对象的引用做到的,所以,引用类型的值是按引用访问的。

这种说法不严密,当复制保存着对象的某个变量时,操作的是对象的引用。但在为对象添加属性时,操作的实际上是对象。

JavaScript中的字符串不是引用类型

动态的属性

对象的实例可以动态添加属性,而基本类型值不能改变。

1
2
3
var book = new Object();
book.name = "JavaScript高级程序设计语言"; //为对象book动态添加属性
alert(book.name); //调用book的name属性

而对于基本数据类型则不可以

1
2
3
var name = "hello";
name.age = 23;
alert(name.age) //undefine

复制变量值

不仅两种类型值得存储方式不一样,在对基本类型值和引用类型值进行复制操作的时候,也存在不同

对基本类型值复制,将会创建一个相同类型的变量,然后在将原变量的值复制给新变量,这时,新变量和原变量两者相互独立。

1
2
var num1 = 5;
var num2 = num1;

此后,两个变量相互独立,对其中一个变量的操作不会影响另一变量

对引用类型值得复制,同样也会将存储在变量对象中的值复制一份放到 为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一 个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另 一个变量,如下面的例子所示:

1
2
3
4
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"

由于是引用类型值,所以两者相互关联

传递参数

ECMAScript 中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参 数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而 引用类型值的传递,则如同引用类型变量的复制一样。

在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,或者用 ECMAScript的概念来说,就是arguments中的一个元素),比如:

1
2
3
4
5
6
7
8
9
function addTen(num) {
num += 10;
return num;
}

var num = 20;
addTen(num);
alert(num); // 20
alert(addTen(num)) // 30

在向参数传递引用类型的值时,会把 这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。比如 :

1
2
3
4
5
6
7
8
9
function setName(obj) {
obj.name = "Xiaohua";
obj = new Object(); //将局部变量obj重新定义了一个对象
obj.name = "Xiaoming"; //并将name属性改为"Xiaoming"
}

var person = new Object();
setName(person);
alert(person.name); //Xiaohua

这里的结果充分反映了,函数参数的传递为值传递,如果这里是引用传递的话,personname属性应该为Xiaoming

检测类型

通常用来检测引用类型的值,比如,我们想知道这是什么类型的对象

操作符instanceof ,比如:

1
2
alert(person instanceof Object);   //变量person是Object吗?
alert(person instanceof Array); //变量person是Array吗?

如果变量的给定的应用类型的实例,则返回true

根据规定,所有的引用类型都是Object的实例

语句

if语句

  • 第一种用法
1
2
3
4
5
if( i > 25 ) {
alert("Greater than 25.");
} else {
alert("Less than or equal to 25.");
}
  • 第二种用法
1
2
3
4
5
6
7
if (i > 25) {
alert("Greater than 25.");
} else if (i < 0) {
alert("Less than 0.");
} else {
alert("Between 0 and 25, inclusive.");
}

do-while语句

后测试语句,循环体的语句至少被执行一次

1
2
3
4
var i = 0;
do {
i += 2;
} while (i < 2); //此时代码块只能被执行一次,也是至少执行的一次,碰到判断条件停止循环

while语句

先判断再执行,代码块的语句有可能永远不能执行

1
2
3
4
var i = 0;
while(i < 10) {
i += 2;
} //先判断是否符合条件,再执行

for语句

前测试循环语句

1
2
3
4
for (initialzation; expression; post-loop-expression) 
{
statement;
}

示例:

1
2
3
4
5
var n = 10;
var j = 0;
for (var i = 0; i < n; i++) {
j += 1;
} //初始化i等于0,判断i小于n,执行代码快里的语句,再执行i++语句,后面依次循环

for-in语句

一种精准的迭代语句,可以用来枚举对象的属性

1
2
3
for ( property in expression) {
statement;
}

示例:

1
2
3
for (var propName in Window) {
document.write(propName);
}

break、continue、label语句

label 语句可以和break,continue在多重循环中搭配使用

1
label: statement;      //label语句的格式

break语句用来完全跳出循环,continue语句用来跳出大循环中的一次循环并开始下一次循环

示例:break

1
2
3
4
5
6
7
var number = 0;
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i == 5 && j == 5) break; //number=55时,退出内层循环,所以少循环了5次
number++;
}
} //number最后的值为95

示例: continue

1
2
3
4
5
6
7
var number = 0;
for (var i = 0; i < 10; i++) {
for (var j =0; j < 10; j++) {
if ( i == 5 && j == 5) continue; //number = 55时,跳过一次内层循环,最后少循环了一次
number++;
}
} //number最后的值为99

示例:break label

1
2
3
4
5
6
7
8
9
10
var number = 0;
start:
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i == 5 && j == 5){
break start;
}
number++;
}
}

循环跳到start标签处,所以number最后的值为55

示例:continue label

1
2
3
4
5
6
7
8
9
10
var number = 0;
start:
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 10; j++) {
if (i == 5 && j == 5){
continue start;
}
number++;
}
} //number = 95

循环跳到label标签处,即就是当满足continue条件时,start标签处的外层循环跳过一次,直接从i= 5,j= 5处进入i = 6,j= 0处,所以number的值最后为95

with语句

with语句的作用是将代码的作用域设置到一个特定的对象中去

with语句可以简化代码,但是同时也会造成性能下降,严格模式下禁用

示例:未使用with语句

1
2
3
var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href;

示例:使用with语句

1
2
3
4
5
with(location) {
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}

switch语句

一个表达式,而需要对表达式的多个值进行不同的处理方式时使用

语法:

1
2
3
4
5
6
7
8
9
10
switch (expression) {
case value1: statement;
break;
case value2: statement;
break;
case value3: statement;
break;
default: statement;
break;
}

示例:

1
2
3
4
5
6
switch (i) {
case 2: alert("2");
break;
case 4: alert("4");
break;
}

可以混合case情形,注意要删去break

1
2
3
4
5
6
7
switch (i) {
case 2:
//合并两种情形
case 4:
alert("4");
break;
}

可以在 switch 语句中使用任何数据类型(在很多其他语言中只能使用数值),无论是字符串,还是对象都没有 问题。其次,每个 case的值不一定是常量,可以是变量,甚至是表达式

1
2
3
4
5
6
7
8
switch ("hello world") {
case "hello" +"world":
alert("Greeting was found.");
break;
case "goodbye":
alert("Closing was found.");
break;
}

switch表达式在与case匹配时,采用全等操作符,故不会发生类型转换,’10’不等于10

操作符

相等操作符

  • 相等和不相等
  • 全等和不全等

由于相等和不相等比较是存在类型转换问题,所以为了保证编程时代码中数据类型的完整性,尽量使用使用全等和不全等

条件操作符

  • variable = Boolean.expression ? true_value : false_value;

赋值操作符

名称 操作符
加/赋值 +=
减/赋值 -=
乘/赋值 *=
除/赋值 /=
模/赋值 %=
左移/赋值 <<=
有符号右移/赋值 >>=
无符号右移/赋值 >>>=

设计这些操作符的目的是为了简化赋值操作,并不会带来任何性能上的提升

逗号操作符

  • 声明多个变量
1
var num1 = 1, num2 = 2, num3 = 3;
  • 赋值操作
1
var num = (4,5,6,7,0);   //num的值为最后一个数,num == 0;

String 类型

1.’ ‘ 或者 “ “ 都可以表示一个字符串
2.字符字面量,就是转义字符

字面量 含义
\n 换行
\t 制表符
\b 空格
\r 回车
\f 进制
\\ 斜杠
\‘ 单引号,如 ‘ It \‘s mine ‘
\“ 双引号, 如 “ He said,\“hi\“ “
\xnn 以十六进制(n为0~f)表示的字符,如’\x41’表示 ‘A’
\unnnn 以十六进制(n为0~f)表示Unicode字符,如’\x03a3’表示希腊字母Σ

3.字符串的长度,length属性

4.字符串不可变,一旦创建,不可修改,字符串的拼接也是重新定义了新的字符串再删除原来的字符串。

5.用toString()方法和String()转换成字符串。

  • 在不知道转换变量是“null”还是“undefined“时,用String()。如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var value1 = 10;      
    var value2 = true;
    var value3 = null;
    var value4

    String(value1); //"10"
    String(value2); //"true"
    String(value3); //"null"
    String(value4); //"undefined"

动画的基础知识

动画是样式随时间变化的的一个很好的例子,简单来说,动画就是元素的位置随时间的变化而发生变化的一种函数。

  1. 位置
    设置元素在网页里的位置的任务一般是属于表示层的,也就是CSS的任务,例子如下:

    1
    2
    3
    4
    5
    element {
    position: absolute;
    top: 100px;
    left: 30px;
    }

    同样也可以用js来设置:

    1
    2
    3
    element.style.position = "absolute";
    element.style.top = "100px";
    element.style.left = "30px";

这就表示了该元素将被摆放在距离网页顶部100px处,距离网页左端30px处,position属性有四个可选择的值。

属性 含义
position static position属性的默认值,元素的位置想会按照元素出现的先后顺序依次出现
position fixed
position relative 表现形式和static相似,区别是position属性值为relative还可以从文档的正常显示顺序里脱离出来
position absolute 如果我某个元素的position值设为absolute,那么我们就可以把它放在容纳它的容器中的任意位置

容器:这里的容器也是一个元素,只不过需要一定的条件

  • 该元素的position属性是fixed或absolute
  • 改元素的父元素的position属性是fixed或absolute

把文档里的元素放在特定的地方不需要花太大的功夫,我们假定就这样一个元素:

1
<p id="message">Woo</p>

用js代码来设置这个元素的初始位置

1
2
3
4
5
6
7
8
function positionMessage() {
if(!document.getElementById) return false;
if(!document.getElementById('message')) return false;
var elem = document.getElementById('message');
elem.style.position = "absolute";
elem.style.top = "100px";
elem.style.left = "30px";
}

现在我们想让这个元素的位置随时间的变化而变化

  1. 时间

接下来会用到的函数:

  • setTimeout( “function“, interval );

    • 第一个参数通常是一个字符串,其内容是要执行的函数的名字。
    • 第二个参数是一个数值,它以毫秒为单位设定了需要经过多长时间才执行第一个参数传给它的函数。
    • 该函数还有一个返回值,当我们想要结束取消一个还在等待执行的函数,就可以把这个函数的返回值赋值给一个变量,然后调用cleanTimeout( )函数。
  • cleanTimeout( );

    • 取消待执行函数的排队。
    1
    2
    var movement = setTimeout( "positionMessage", 5000 );    //让函数positionMessage()5000毫秒后执行
    cleanTimeout( movment ); //取消执行
  1. 时间递增量

我们需要对我们函数进行升级,即使使用了setTimeout( )函数,这个元素的行为依然不像动画,只不过是过了一段时间后突然跳到另一个位置

首先设定一个目标位置值,在positionMessage( )函数中递增top和left的值,直到达到目标值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function messageMove() {
if (!document.getElementById) return false;
if (!document.getElementById("message")) return false;
var elem = document.getElementById("message");
var ypos = parInt(elem.style.top);
var xpos = parInt(elem.style.left);
if (xpos == 200 && ypos == 200) {
return true;
}
if (xpos < 200) xpos++;
if (ypos < 200) ypos++;
if (xpos > 200) xpos--;
if (ypos > 200) ypos--;
elem.style.top = ypos + 'px';
elem.style.left = xpos + 'px';
movement = setTimeout("positionMessage",10);
}