类的创建和继承
类的创建(es5):new 一个 function,在这个 function 的 prototype 里面增加属性和方法。
对象创建的方式有哪些?
在 JavaScript 中,对象可以通过以下几种方式进行创建:
-
对象字面量(Object Literal): 使用花括号
{}来定义一个对象,可以在花括号中添加属性和方法。const obj = {
property1: value1,
property2: value2,
method: function() {
// 方法的定义
}
}; -
构造函数(Constructor): 使用构造函数创建对象,通过
new关键字调用构造函数,并使用this关键字在构造函数中定义属性和方法。function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
};
}
const person = new Person('John', 30); -
Object.create() 方法: 使用
Object.create()方法创建一个新对象,以指定的原型对象作为新对象的原型。const prototypeObj = {
property1: value1,
property2: value2,
method: function() {
// 方法的定义
}
};
const newObj = Object.create(prototypeObj); -
类(Class): 在 ES6 以后,JavaScript 引入了类(class)的概念,可以使用
class关键字定义一个类,然后使用new关键字创建该类的实例对象。class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name}`);
}
}
const person = new Person('John', 30); -
工厂函数(Factory Function): 使用一个函数来返回一个新的对象,该函数被称为工厂函数,通过调用该函数可以创建多个类似的对象。
function createPerson(name, age) {
return {
name: name,
age: age,
sayHello: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
}
const person = createPerson('John', 30);
以上是常用的对象创建方式,每种方式都有自己的特点和适用场景。根据实际需求,选择合适的方式来创建对象。
类的继承
- 类的继承——原型链继承
function Cat(){ }
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
缺陷:当通过cat修改引用类型的属性时候,会污染原型链上的属性,影响到所有实例。也不能多继承。
cat.sleep = function() {
console.log('cat 修改了这个方法');
}
var cat2 = new Cat();
console.log(cat.sleep()); // cat 修改了这个方法
- 构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给 子类(没用到原型)
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
特点:可以实现多继承 缺点:只能继承父类实例的属性和方法,不能继承原型上的属性和方法。
- 实例继承和拷贝继承
实例继承:为父类实例添加新特性,作为子类实例返回 拷贝继承:拷贝父类元素上的属性和方法 上述两个实用性不强,不一一举例。
- 组合继承:相当于构造继承和原型 链继承的组合体。通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
特点:可以继承实例属性/方法,也可以继承原型属性/方法 缺点:调用了两次父类构造函数,生成了两份实例
- 寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// 创建一个没有实例方法的类
var Super = function(){};
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
较为推荐
FAQ?
能不能手动实现一下instanceof的功能?
function myInstanceof(left, right) {
//基本数据类型直接返回false
if(typeof left !== 'object' || left === null) return false;
//getProtypeOf是Object对象自带的一个方法,能够拿到参数的原型对象
let proto = Object.getPrototypeOf(left);
while(true) {
//查找到尽头,还没找到
if(proto == null) return false;
//找到相同的原型对象
if(proto == right.prototype) return true;
proto = Object.getPrototypeOf(proto);
}
}