以下是详细讲解JavaScript高级程序设计(第三版)学习笔记6、7章的完整攻略。
6章 对象
6.1 创建对象
6.1.1 工厂模式创建对象
工厂模式是一种常用的对象创建方法,使用函数创建对象可以解决创建多个类似对象的问题,但无法解决对象识别的问题(即无法通过某种方式判断一个对象的类型)。使用工厂模式创建的对象无法识别其类型,只能通过检查其属性来判断对象类型。
以下是使用工厂模式创建对象的示例代码:
function createPerson(name, age) {
let person = new Object();
person.name = name;
person.age = age;
person.sayName = function() {
console.log(this.name);
};
return person;
}
let person1 = createPerson('Tom', 18);
let person2 = createPerson('Jerry', 20);
person1.sayName(); // 输出 "Tom"
person2.sayName(); // 输出 "Jerry"
6.1.2 构造函数创建对象
构造函数在执行时,会创建一个新的对象,将this关键字绑定到对象上,并自动在对象上创建出必要的属性和方法。使用构造函数创建的对象可以通过instanceof操作符来判断对象类型,但是每个方法都需要重新定义,会占用过多内存。
以下是使用构造函数创建对象的示例代码:
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
};
}
let person1 = new Person('Tom', 18);
let person2 = new Person('Jerry', 20);
person1.sayName(); // 输出 "Tom"
person2.sayName(); // 输出 "Jerry"
console.log(person1 instanceof Person); // 输出 true
console.log(person2 instanceof Person); // 输出 true
6.1.3 原型模式创建对象
使用原型模式创建对象可以共享方法和属性,可以大大减少内存占用。原型模式创建的对象其类型是一致的,但所有实例共享同一个属性或方法,如果某个实例修改了共享的属性,将会影响到所有实例。
以下是使用原型模式创建对象的示例代码:
function Person() {
}
Person.prototype.name = "Tom";
Person.prototype.age = 18;
Person.prototype.sayName = function() {
console.log(this.name);
};
let person1 = new Person();
let person2 = new Person();
person1.sayName(); // 输出 "Tom"
person2.sayName(); // 输出 "Tom"
console.log(person1 instanceof Person); // 输出 true
console.log(person2 instanceof Person); // 输出 true
6.1.4 组合使用构造函数和原型模式创建对象
组合使用构造函数和原型模式创建对象可以解决私有属性和共有属性的问题,既可以共享方法和属性,也可以使每个对象都有自己的属性。
以下是组合使用构造函数和原型模式创建对象的示例代码:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function() {
console.log(this.name);
};
let person1 = new Person('Tom', 18);
let person2 = new Person('Jerry', 20);
person1.sayName(); // 输出 "Tom"
person2.sayName(); // 输出 "Jerry"
console.log(person1 instanceof Person); // 输出 true
console.log(person2 instanceof Person); // 输出 true
6.2 对象的继承
6.2.1 原型链继承
原型链继承是通过将一个对象的原型指向另一个对象,使得前者可以访问到后者的属性和方法,从而实现继承。但是使用原型链继承可能会导致属性共享和无法传递参数的问题。
以下是使用原型链继承的示例代码:
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
};
let instance = new SubType();
console.log(instance.getSuperValue()); // 输出 true
console.log(instance.getSubValue()); // 输出 false
console.log(instance instanceof SuperType); // 输出 true
console.log(instance instanceof SubType); // 输出 true
6.2.2 借用构造函数继承
借用构造函数继承是通过在子类构造函数内部调用父类构造函数,从而继承父类的属性和方法。但是使用这种方法只能继承父类的实例属性和方法,无法继承父类原型中定义的属性和方法。
以下是使用借用构造函数继承的示例代码:
function SuperType(name) {
this.name = name;
}
function SubType() {
SuperType.call(this, "Tom");
this.age = 18;
}
let instance = new SubType();
console.log(instance.name); // 输出 "Tom"
console.log(instance.age); // 输出 18
6.2.3 组合继承
组合继承是通过同时使用原型链继承和借用构造函数继承来实现继承,既可以继承父类原型中的属性和方法,又可以继承父类的实例属性和方法。
以下是使用组合继承的示例代码:
function SuperType(name) {
this.name = name;
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SubType.prototype = new SuperType();
let instance = new SubType("Tom", 18);
console.log(instance.name); // 输出 "Tom"
console.log(instance.age); // 输出 18
instance.sayName(); // 输出 "Tom"
console.log(instance instanceof SuperType); // 输出 true
console.log(instance instanceof SubType); // 输出 true
6.3 对象的拷贝
对象的拷贝可以使用深拷贝和浅拷贝两种方式来实现。浅拷贝只会拷贝对象的属性值,而不会拷贝对象的属性所指向的实际对象。深拷贝会拷贝对象的属性以及该属性所指向的对象。
以下是使用浅拷贝和深拷贝的示例代码:
// 浅拷贝示例
let obj = {name: "Tom", age: 18};
let obj2 = obj;
obj.name = "Jerry";
console.log(obj2.name); // 输出 "Jerry"
// 深拷贝示例
function deepCopy(obj) {
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === "object") {
result[key] = deepCopy(obj[key]);
} else {
result[key] = obj[key];
}
}
}
return result;
}
let obj = {name: {first: "Tom", last: "Jerry"}, age: 18};
let obj2 = deepCopy(obj);
obj.name.first = "Jerry";
console.log(obj2.name.first); // 输出 "Tom"
7章 函数表达式
7.1 递归
递归指的是函数调用自身的过程,可以使用递归来实现一些逻辑上复杂的功能,但是过多的递归可能会导致栈内存溢出的问题。
以下是使用递归实现阶乘的示例代码:
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * factorial(num - 1);
}
}
console.log(factorial(5)); // 输出 120
7.2 闭包
闭包是指一个函数可以访问和操作外部函数的变量和参数,从而可以访问函数执行时的作用域链中的变量。使用闭包可以实现数据私有化,即保护变量不受其他代码的干扰和污染。
以下是使用闭包实现数据私有化的示例代码:
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
},
getCount: function() {
return count;
}
};
}
let counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 输出 1
7.3 立即调用函数表达式(IIFE)
立即调用函数表达式(IIFE)是指一个函数在定义时立即执行,可以用来创建局部作用域、保护命名空间和防止变量污染等。
以下是使用立即调用函数表达式(IIFE)创建局部作用域的示例代码:
(function() {
let message = "Hello, world!";
console.log(message);
})();
console.log(message); // 抛出未定义错误
7.4 函数绑定
函数绑定是指通过函数的bind()方法来改变函数内部this的指向,使其指向其他对象,从而实现函数调用时this指向的指定。
以下是使用函数绑定修改函数内部this指向的示例代码:
let obj1 = {
name: "Tom"
};
let obj2 = {
name: "Jerry"
};
function sayName() {
console.log(this.name);
}
let sayName1 = sayName.bind(obj1);
let sayName2 = sayName.bind(obj2);
sayName1(); // 输出 "Tom"
sayName2(); // 输出 "Jerry"
至此,JavaScript高级程序设计(第三版)学习笔记6、7章的完整攻略已经介绍完毕。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript高级程序设计(第三版)学习笔记6、7章 - Python技术站