本文出自 MDN
1.命名空间(Namespace)
使用命名空间也最大程度地减少应用程序的名称冲突的可能性。
命名空间是一个容器,它允许开发人员在一个独特的,特定于应用程序的名称下捆绑所有的功能。 在JavaScript中,命名空间只是另一个包含方法,属性,对象的对象。
// 给普通方法和属性创建一个叫做MYAPP.commonMethod的容器
MYAPP.commonMethod = {
regExForName: "", // 定义名字的正则验证
regExForPhone: "/\d{3}-\d{8}|\d{4}-\d{7}/", // 定义电话的正则验证
validateName: function(name){
// 对名字name做些操作,你可以通过使用“this.regExForname”
// 访问regExForName变量
},
validatePhoneNo: function(phoneNo){
if(!this.regExForPhone.test(phoneNo)) {
throw new Error("验证失败");
}
}
}
// 对象和方法一起申明
MYAPP.event = {
addListener: function(el, type, fn) {
el.addEventListener(type, fn);
},
removeListener: function(el, type, fn) {
el.removeEventListener(type,fn);
},
getEvent: function(el) {
return getEventListeners(el);
}
// 还可以添加其他的属性和方法
}
//使用addListener方法的写法:
MYAPP.event.addListener(div, "click", callback);
2.标准内置对象(全局的对象)
挂载在javaScript全局上的对象,JavaScript 中的每个对象都是 Object 对象的实例且继承它所有的属性和方法。
3.自定义对象(类)
JavaScript 面对对象编程,不是基于“类”的实现,而是基于构造函数(constructor)和原型链(prototype)去实现的。
3.1 类的实例
在下面的示例中,我们定义了一个名为Person的类,然后我们创建了两个Person的实例
function Person() { }
var person1 = new Person();
var person2 = new Person();
注意:有一种新增的创建未初始化实例的实例化方法 Object.create
3.2 构造函数
构造函数名字的第一个字母通常大写, 函数体内部使用了this关键字,代表了所要生成的对象实例,生成对象的时候,必须使用new命令。
对象实例被创建时,构造器就会被调用,构造器是对象中的一个方法。 在JavaScript中函数就可以作为构造器使用,因此不需要特别地定义一个构造器方法,每个声明的函数都可以在实例化后被调用执行,构造器常用于给对象的属性赋值或者为调用函数做准备。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。
function Person() {
alert('Person instantiated');
}
var person1 = new Person();
3.3 属性(对象属性)
属性就是 类中包含的变量;每一个对象实例有若干个属性. 为了正确的继承,属性应该被定义在类的原型属性 (函数)中。
function Person(firstName) {
this.firstName = firstName;
alert('Person instantiated');
}
var person1 = new Person('Alice');
var person2 = new Person('Bob');
// Show the firstName properties of the objects
alert('person1 is ' + person1.firstName); // alerts "person1 is Alice"
alert('person2 is ' + person2.firstName); // alerts "person2 is Bob"
3.4 方法(对象方法)
定义一个方法, 需要将一个函数赋值给类的 prototype 属性; 这个赋值给函数的名称就是用来给对象在外部调用它使用的。
function Person(firstName) {
this.firstName = firstName;
}
Person.prototype.sayHello = function() {
alert("Hello, I'm " + this.firstName);
};
var person1 = new Person("Alice");
var person2 = new Person("Bob");
// call the Person sayHello method.
person1.sayHello(); // alerts "Hello, I'm Alice"
person2.sayHello(); // alerts "Hello, I'm Bob"
3.5 继承
创建一个或多个类的专门版本类方式称为继承(Javascript只支持单继承)。 创建的专门版本的类通常叫做子类,另外的类通常叫做父类。 在Javascript中,继承通过赋予子类一个父类的实例并专门化子类来实现。在现代浏览器中你可以使用 Object.create 实现继承。
// 定义Person构造器
function Person(firstName) {
this.firstName = firstName;
}
// 在Person.prototype中加入方法
Person.prototype.walk = function(){
alert("I am walking!");
};
Person.prototype.sayHello = function(){
alert("Hello, I'm " + this.firstName);
};
// 定义Student构造器
function Student(firstName, subject) {
// 1.调用父类构造器, 指向当前子类的this指向,这样父类的属性和原型方法中的this都指向子类。
Person.call(this, firstName);
// 初始化Student类特有属性
this.subject = subject;
};
// 2.把子类的原型对象赋值成一个继承了父类的原型对象的对象。
// 注意: 常见的错误是使用 "new Person()"来建立Student.prototype.
// 这样做的错误之处有很多, 最重要的一点是我们在实例化时
// 不能赋予Person类任何的FirstName参数
// 调用Person的正确位置如下,我们从Student中来调用它
Student.prototype = Object.create(Person.prototype); // See note below
// 3.设置"constructor" 属性指向Student
Student.prototype.constructor = Student;
// 更换"sayHello" 方法
Student.prototype.sayHello = function(){
console.log("Hello, I'm " + this.firstName + ". I'm studying " + this.subject + ".");
};
// 加入"sayGoodBye" 方法
Student.prototype.sayGoodBye = function(){
console.log("Goodbye!");
};
// 测试实例:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello(); // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk(); // "I am walking!"
student1.sayGoodBye(); // "Goodbye!"
// Check that instanceof works correctly
console.log(student1 instanceof Person); // true
console.log(student1 instanceof Student); // true
3.6 继承的演变
1.借用构造函数继承
缺点: 只能继承父类构造器的属性和方法,无法继承父类的原型属性和原型方法。
function Person() {
this.name = "父类";
}
Person.prototype.say = function() {console.log("我是" + this.name)}
function Student() {
Person.call(this, "子类");
this.age = 20;
}
var student1 = new Student();
student1.name // "父类"
student1.say() // Uncaught TypeError: student1.say is not a function at <anonymous>:1:8
2.借用原型链继承(解决了上述没有继承父类原型的问题)
缺点:其中一个实例改变了引用类型的值,会影响到另外一个实例的值。
function Person() {
this.name = "父类";
this.stature = {
height: 1700,
width: 1000,
}
}
Person.prototype.say = function () {
console.log("这是父类的方法");
}
function Student() {}
Student.prototype = new Person();
var student1 = new Student();
var student2 = new Student();
student1.stature.height = 1800;
student2.stature.height // 1800
3.组合式继承(通过上面两种方式的组合,解决了引用同一个对象的问题)
缺点:每次创建实例的时候,都执行了父类的构造函数。
function Person() {
this.name = "父类";
this.stature = {
height: 1700,
width: 1000,
}
}
Person.prototype.say = function () {
console.log("这是父类的方法");
}
function Student() {
Person.call(this);
}
Student.prototype = new Person();
var student1 = new Student();
var student2 = new Student();
student1.stature.height = 1800;
student2.stature.height // 1700
- 组合式继承优化(解决了上一个例子的重复执行父类的构造函数的问题)
缺点:实例的构造函数指向了父类的构造函数。
function Person() {
this.name = "父类";
this.stature = {
height: 1700,
width: 1000,
}
}
Person.prototype.say = function () {
console.log("这是父类的方法");
}
function Student() {
Person.call(this);
}
Student.prototype = Person.prototype;
var student1 = new Student();
var student2 = new Student();

下图一:Student.prototype = Person.prototype 会导致父类的构造函数也指向Student。
下图二:使用Object.create,会生成一个全新的对象, 完美解决了同一个对象引用的问题。
function Person() {
this.name = "父类";
this.stature = {
height: 1700,
width: 1000,
}
}
Person.prototype.say = function () {
console.log("这是父类的方法");
}
function Student() {
Person.call(this);
}
// Student.prototype = Person.prototype;
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
var student1 = new Student();
var student2 = new Student();
图一:


3.7 封装
在上一个例子中,Student类虽然不需要知道Person类的walk()方法是如何实现的,但是仍然可以使用这个方法;Student类不需要明确地定义这个方法,除非我们想改变它。 这就叫做封装,对于所有继承自父类的方法,只需要在子类中定义那些你想改变的即可。