1、弱类型语言:
JavaScript
是弱类型语言。但所谓言
弱类型语言
,只表明该语言在表达式运
算中不强制校验运算元的数据类型,而并不表明该语言是否具有类型系统。
2、
JavaScript 识别6 种数据类型,并在运算过程中自动处理语言类型的转换。
2.1
6种数据类型:
undefine、number、string、boolean、function、object,
typeof
运算总是以字符串形式返回上述
6
种类型值之一。
2.2
变量的两种类型:
1)基本类型在内存中具有固定的大小,而引用类型则不同。例如,对象可以具有任意的长度,无固定大小。数组也是。
2)基本类型变量存的是数据的具体值,而引用类型变量保存的是值的引用。
基本类型:
undefine、number、boolean
、
string
引用类型:
function、object
3、NaN 值:
至少表面上来看, 一个值应该与其自身“ 等值
/
全等”。但事实上,在
JavaScript
中存在一个例外:一个
NaN
值,与自身并不等值,也不全等。
4、
空字符串用作对象成员。
在
JavaScript
中也可以用一对不包含任意字符的单引号与双引号来表示一
个空字符串(
Null String
),其长度值总是为
0
。比较容易被忽视的是,空字符
串与其它字符串一样也可以用作对象成员。
object{
'':100;
}
alert(''); //100
5、相等运算符 == 和等同运算符 === 。
1) === 运算符是等同运算符,它采用严格的同一性定义检测两个运算数是否完全等同。
2)== 运算符是相等运算符,它采用比较宽松的同一性定义(即允许进行类型转换)检测两个运算数是否相等。
下面的规则用于判定
===
运算符比较的两个值是否完全相等:
1.如果两个值的类型不同,它们就不相同。
2.如果两个值的类型是数字,而且值相同,那么除非其中一个或者两个都是NaN(这种情况它们不是等同的),否则他们是等同的。值NaN永远不会与其他的任何值等同,包括它自身。
3.如果两个值都是字符串,而且在串中的同一位置上的字符完全相同,那么它们就完全等同。如果字符串的长度或内容不同,它们就不是等同的。
4.如果两个值都是布尔值true,或者两个值都是布尔值false,那么它们等同。
5.如果两个值引用的是同一个对象,数组或函数,那么它们完全等同。如果它们引用的是不同的对象(数组或函数),它们就不完全等同,即使这两个对象具有完全相同的属性或两个数组具有完全相同的元素。
6.如果两个值都是null或都是undefined,它们完全相同。
下面的规则用于判定 ==运算符比较的两个值是否相等:
1.如果两个值具有相同的类型,那么就检测它们的等同性。如果这两个值完全相同,它们就相等。如果它们不完全相同,则它们不相等。
2.如果两个值的类型不同,它们仍然可能相等。用下面的规则和类型转换来检测它们的相等性:
2.1 如果一个值是null,另一个值是undefined,它们相等。
2.2 如果一个值是数字,另一个值是字符串,把字符串转换为数字,再用转换后的值进行比较。
2.3 如果一个值是true,将它转换成1,再进行比较。如果一个值为false,把它转换成0,再进行比较。
2.4 如果一个值是对象,另一个值是数字或者字符串,将对象转换成原始类型的值,再进行比较。
2.5 其他的数值组合是不相等的。
1.如果两个值的类型不同,它们就不相同。
2.如果两个值的类型是数字,而且值相同,那么除非其中一个或者两个都是NaN(这种情况它们不是等同的),否则他们是等同的。值NaN永远不会与其他的任何值等同,包括它自身。
3.如果两个值都是字符串,而且在串中的同一位置上的字符完全相同,那么它们就完全等同。如果字符串的长度或内容不同,它们就不是等同的。
4.如果两个值都是布尔值true,或者两个值都是布尔值false,那么它们等同。
5.如果两个值引用的是同一个对象,数组或函数,那么它们完全等同。如果它们引用的是不同的对象(数组或函数),它们就不完全等同,即使这两个对象具有完全相同的属性或两个数组具有完全相同的元素。
6.如果两个值都是null或都是undefined,它们完全相同。
下面的规则用于判定 ==运算符比较的两个值是否相等:
1.如果两个值具有相同的类型,那么就检测它们的等同性。如果这两个值完全相同,它们就相等。如果它们不完全相同,则它们不相等。
2.如果两个值的类型不同,它们仍然可能相等。用下面的规则和类型转换来检测它们的相等性:
2.1 如果一个值是null,另一个值是undefined,它们相等。
2.2 如果一个值是数字,另一个值是字符串,把字符串转换为数字,再用转换后的值进行比较。
2.3 如果一个值是true,将它转换成1,再进行比较。如果一个值为false,把它转换成0,再进行比较。
2.4 如果一个值是对象,另一个值是数字或者字符串,将对象转换成原始类型的值,再进行比较。
2.5 其他的数值组合是不相等的。
6、delete 运算符:
6.1
delete
可以删除很多东西
(
包括对象成员和数组元素
)
,但它不能删除:
1)
用
var
声明的变量;
2)直接继承自原型的成员。
var obj = {
method : function() { },
prop : 1234
}
golbal_value = 'abcd';
array_value = [0,1,2,3,4];
function testFunc() {
value2 = 1234;
delete value2;
}
// 调用testFunc() 函数,函数内部的delete 用法也是正确的
testFunc();
// 以下四种用法都是正确的
delete obj.method;
delete obj[ 'prop' ];
delete array_value[ 2 ];
delete golbal_value;
delete 不能删除继承自原型的成员。但如果你修改了这个成员的值,你仍然可以删除它,这将使它恢复到原型的值。关于这一点的真相,是 delete 运算事实上是删除了实例的成员表中的值。
6.2
delete
仅在删除一个不能删除的成员时,才会返回
false
。其
它情况下,例如删除不存在的成员,或者继承自父代类/原型的成员,都
将返回
true
。
function MyObject() {
}
MyObject.prototype.value = 100;
// 该成员继承自原型,且未被重写, 删除返回true.
// 由于delete 操作不对原型产生影响, 因此obj1.value 的值未变化.
var obj1 = new MyObject();
alert( delete obj1.value );
alert( obj1.value );
// 尝试删除Object.prototype ,该成员禁止删除, 返回false
alert( delete Object.prototype );
7、对象及其成员的检查:
7.1
in 运算。
7.2 instanceof :
insta nceof
将会检测类的继承关系。
// 声明构造器
function MyObject( ) {
// ...
}
// 实例创建
var obj = new MyObject( );
// 显示 true
alert( obj instanceof MyObject );
function MyObjectEx( ) {
// ...
}
//原型链
MyObjectEx.prototype = new MyObject( );
// 实例创建
var obj2 = new MyObjectEx( );
// 检测构造类, 显示 true
alert( obj2 instanceof MyObjectEx );
// 检测父类, 显示 true
alert( obj2 instanceof MyObject );
7.3
propertyIsEnumerable
的一个实现版本,
该方法是不检测对象的原型链的
。
//code from Qomo Project.
Object.prototype.propertyIsEnumerable = function(proName) {
for ( var i in this ) {
if ( i == proName ) break;
}
if ( i != proName ) return false;
// if clone from prototype, return false.
return this[ proName ] !== this.constructor.prototype[proName];
}
当某个对象成员不存在, 或它不可列举时, 则对该成员调用
propertyIsEnumera ble()
方法将返回
false
—— 比较常见的情况是,
JavaScript
对
象的内置成员是不能被列举的。
var obj = new Object();
// 不存在'aCustomMember', 显示false
alert( obj.propertyIsEnumerable('aCustomMember') );
// 内置成员不能被列举,这种情况下,你可以用 in 运算检测到该成员,但不能用 for..in 语句来列举它。
alert( obj.propertyIsEnumerable( 'constructor' ) );
8、缺省对象的指定:with语句。
// 示例1: 存取对象成员
var obj = new Object( );
obj.value = 100;
// 示例2: 访问(全局的)对象或值
value = 1000;
with ( obj ) {
value *= 2;
}
alert( obj.value ); //200
alert( value ); //100
9、
//声明对象直接量
var obj = {
v1: 1,
v2: 2,
v3: 3
}
10、[ ] 的二义性:
数组声明、
数组下标运算符、对象成员的存取运算符。
a = [ [ ][ 100 ] ]; // 第一个数组为空数组, 第二个数为任意数值,都将得到[ undefined ]
a = [ [ 1, 2, 3 ][ 2 ] ]; // 第一个数组有三个元素,因此arr[2] 是存在的,故而得到[ 3 ]
a = [ [ ][ ] ]; // 第一个数组为空,是正常的;但第二个作为下标运算时缺少索引,故语法错
11、语法作用域
分表达式(一级)、语句、函数、全局四级
1)语法作用域是互不相交的。正是作用域互不相交的特性构造了代码结构化的层
次,并消除了一些错误隐患。
2)
语法作用域间可以存在平行或包含关系。
高级别可以嵌套低级别的语法作用
域,反之则不成立。
3)高级别的流程变更子句(或语句)可以跨越低级别的作用域,反之则不行。
11、变量作用域
表达式级、函数(局部)级、全局,JavaScript 不存在语句级别的变量作用域。在全局范围内使用 for 循环的同时声明变量,该变量是全局变量。
12、由于JavaScript 是动态语言,因此它只能依赖“变量作用域”来实现封装特性。
13、对象的多态性被转换为运行期的动态特性—— 例如我们可以动态地添加对象的方法/成员,使它看起来象是某个对象。
14、类抄写与原型继承:
1)
类抄写时成员访问效率更高,但内存占用较大;而原型继承反之。
2)
类抄写不依赖内部原型链来维护继承关系,因此也不能通过
instanceof
来做这
种检测;原型继承却可以在
new
运算时维护这种继承关系,也可以检测之。
15、非惰性求值
/**
* 示例1:在参数中使用表达式时的求值规则
*/
var i = 100;
alert( i+=20, i*=2, 'value: '+i ); //120
alert( i ); //240
16、callee
从
JavaScript 1.2
开始使
arguments
对象拥有一个成员:
callee
,该成员
总是指向该参数对象
(Arguments)
的创建者函数。由于
arguments
总是在函数内
部可以直接访问,因此也就总是可以在函数内部识别“我是谁”。
这样一来,无论是否匿名,函数的递归就总是可以写成:(callee
解决了匿名递归的问题
)
void function() {
// ...(略)
arguments.callee();
}();
17、caller
caller
是
Function
的一个成员,指向函数调用者。
18、null是一个object实例(空对象),
typeof null的值是object。