JavaScript语法
1.1 区分大小写
1.2 标识符按一下规则组合:
(1)第一个字符必须是一个字母、下划线(_)或一个美元符号($)
(2)其他字符可以是字母、下划线、美元符号或数字
1.3 严格模式:"use strict";
1.4 值类型:Undefined,Boolean,Number,String
1.5 引用类型:Null,Object
1.6 检测类型
(1)typeof操作符
字符串、数值、布尔值、undefined分别返回string、number、boolean、undefined。
对象和null则返回object。
例如:var s = "Today"; alert( typeof s); // string
(2)instanceof操作符
用于判断对象类型,例如:alert(colors instanceof Array); // 变量colors是Array吗?
2 执行环境及作用域
2.1 定义
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。全局执行环境是最外围的一个执行环境,在Web浏览器中,全局执行环境被定义为window对象。当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。嵌套函数通过作用域链由里到外一层层搜索使用的变量和函数。
2.2 延迟作用域链
(1)try-catch语句的catch块
(2)with语句
2.3 没有块级作用域
注:
(1)由for语句创建的变量i即使在for循环执行结束后,也依旧会存在于循环外部的执行环境中。
(2)使用var声明的变量会自动被添加到最接近的环境中,而初始化变量没有使用var声明的,就会被添加到全局环境。
3 Object类型
3.1 创建Object对象
(1)使用new操作符
var person = new Object();
persion.name = "Tom";
persion.age = 30;
(2)使用对象字面量表示法
var persion = {
name : "Tom",
age : 30
}
或者
var persion = {};
persion.name = "Tom";
persion.age = 30;
3.2 创建Array对象
(1)使用Array构造函数
var colors = new Array();
var colors = new Array(20); // 长度为20的数组
var colors = new Array("red", "blue", "green");
(2)使用数组字面量表示法
var colors = ["red", "blue", "green"];
var colors = []; // 创建空数组
4 Function类型
4.1 函数实际上是对象。
函数名实际上是对象名,因此函数是没有重载的。
ECMAScript函数不介意传递的参数个数和类型,函数体内可以通过arguments对象访问参数数组。
4.2 创建Function
(1)函数声明
alert(sum(10, 10));
function sum(num1, num2){
return num1 + num2;
}
(2)函数表达式
alert(sum(10, 10));// 运行错误,sum未定义
var sum = function(num1, num2){
return num1 + num2;
};
注:在代码开始执行之前,解释器就已经通过一个名为函数声明提升的过程,读取并将函数声明添加到执行环境中,而函数表达式则只是变量声明。
4.3 因为函数名本身就是变量,所以函数也可以作为值来使用,譬如用于函数参数。
4.4 函数内部属性
(1)在函数内部,有两个特殊的对象:arguments和this。
注:在ECMAScript5页规范了另一个函数对象的属性:caller。这个属性保持调用当前函数的函数的引用。
arguments有一个callee属性,是一个指针,指向拥有这个arguments对象的函数。
this引用的是函数据以执行的环境对象——也就是函数对象本身,在全局环境this对象引用的就是window。
(2)每个函数都包含两个属性:length和prototype
length属性表示函数希望接收的命名参数的个数。
prototype属性是最耐人寻味。
(3)每个函数都包含两个非继承而来的方法:apply()和call()
这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
它们强大的地方是能够扩充函数赖以运行的作用域。
apply()方法和call()方法的作用相同,接收的第一个参数都是运行函数的作用域,区别是apply()接收的第二个参数是数组,而call()剩下的参数需要逐个列出来。
注:ECMAScript5还定义了一个方法:bind()。用这个方法创建一个函数实例,其this值会被绑定到传给bind()函数的值。
例子:
window.color = "red";
var o = { color : "blue" };
funciton sayColor(){
alert(this.color);
}
var objSayColor = sayColor.bind(o);
sayColor(); // red
sayColor.call(window); // red
sayColor.call(o); // blue
objSayColor(); // blue
4.5闭包
闭包是指有权访问另一个函数作用域中的变量的函数。
创建闭包的常见方式,就是在一个函数内部创建另一个函数。
例子:
var name = "The window";
var obj = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
}
}
};
var obj2 = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
}
}
};
alert(obj.getNameFunc()()); // The window
alert(obj.getNameFunc().call(obj));// My Object
alert(obj2.getNameFunc()()); // My Object
4.6模仿块级作用域
(1)用作块级作用域(通常称为私有作用域)的匿名函数语法如下:
(function(){
// 这里是块级作用域
})();
(2)私有变量
严格来讲,所有对象属性都是公有的。但有一个私有变量的概念:
任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量。
我们把有权访问私有变量和私有函数的公有方法称为特权方法。
例子:
function MyObject(){
// 私有变量和函数
var privateVariable = 10;
function privateFunction(){
return false;
}
// 特权方法
this.publicMethod = function(){
privateVariable++;
return privateFunction();
}
}
5面向对象的程序设计
5.1属性类型
(1)数据属性
[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。这个属性默认值为ture。
[[Enumerable]]:表示能否通过for-in循环返回属性。这个属性默认值为ture。
[[Writable]]:表示能否修改属性的值。这个属性默认值为ture。
[[Value]]:包含这个属性的数据值。这个属性默认值为undefined。
例子:
var person = { };
object.defineProperty(persion, "name", {
configurable : false,
writable : false,
value : "Tom"
});
alert(person.name); // Tom
person.name = "Greg";
alert(person.name); // Tom
delete person.name;
alert(person.name); // Tom
(2)访问器属性
[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。这个属性默认值为ture。
[[Enumerable]]:表示能否通过for-in循环返回属性。这个属性默认值为ture。
[[Get]]:在读取属性时调用的函数。默认值为undefined。
[[Set]]:在写入属性时调用的函数。默认值为undefined。
例子:
var book = {
_year : 2004,
edition :1
};
Object.defineProperty(book, "year", {
get : function(){
return this._year;
},
set : function(newValue){
if(newValue > 2004){
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
book.year = 2005;
alert(book.edition); // 2
5.2创建对象
(1)工厂模式
function createPerson(name, age){
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function(){
alert(this.name);
};
return o;
}
var person1 = createPerson("Tom", 30);
(2)构造函数模式
function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Tom", 30);
(3)原型模式
function Person(){
}
Person.prototype.name = "Tom";
Person.prototype.age = 30;
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName(); // Tom
var person2 = new Person();
person2.sayName(); // Tom
alert(person1.sayName == person1.sayName); // true
注:hasOwnProperty()方法可以坚持一个属性时存在于实例中还是原型中。
alert(person1.hasOwnProperty("name"); // false
person1.name = "Greg";
alert(person1.name); // Greg
alert(person1.hasOwnProperty("name"); // true
注:in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。
alert("name " in person1); // true
function Person(name, age){
this.name = name;
this.age = age;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructo : Person,
sayName : function(){
alert(this.name);
}
};
var person1 = new Person("Greg", 29);
var person2 = new Person("Tom", 27);
person1.friends.push("Van");
alert(person1.friends); // Shelby, Court, Van
alert(person2.friends); // Shelby, Court
alert(person1.friends == person1.friends); // false
alert(person1.sayName == person1.sayName); // true
所有的引用类型默认都继承了Object,而这个继承是通过原型链实现的。
(1)原型链
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
// 继承SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); // true
alert(instance instanceof Object); // true
alert(instance instanceof SuperType); // true
alert(instance instanceof SubType); // true
(2)借用构造函数
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
function SubType(){
// 继承SuperType
SuperType.call(this, "Tom");
this.age = 29;
}
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); // red, blue, green, black
var instance2 = new SubType();
alert(instance2.colors); // red, blue, green
组合继承是JavaScript最常用的继承模式。它将原型链和借用构造函数的技术组合在一起。
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Greg", 29);
instance1.colors.push("black");
alert(instance1.colors); // red, blue, green, black
instance1.sayName(); // Greg
instance1.sayAge(); // 29
var instance2 = new SubType("Tom", 30);
alert(instance2.colors); // red, blue, green
instance2.sayName(); // Tom
instance2.sayAge(); // 30
function object(o){
function F( ){ };
F.prototype = o;
return new F();
}
// 下面是实例
var person = {
name : "Nicholas",
friends : ["Shelby", "Court"]
}
var anotherPerson = object(person);
anotherPerson = "Greg";
anotherPerson.friends.push("Van");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
anotherPerson.friends.push("Rob");
alert(person.friends); // Shelby, Court, Van, Rob
寄生式继承是与原型式继承紧密相关的一种思路。
function createAnother(original){
var clone = object(original); // 通过调用函数创建一个新对象
clone.sayHi = function(){ // 以某种方式来增强这个对象
alert("Hi");
};
return clone; // 返回这个对象
}
// 下面是实例
var person = {
name : "Nicholas",
friends : ["Shelby", "Court"]
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // hi
(6)寄生组合式继承
// 寄生式组合式继承的基本模式
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); // 创建对象
prototype.constructor = subType; // 增强对象
subType.prototype = prototype; // 指定对象
}
// 下面是实例
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
}