// 1. 每个函数都有 prototype 属性
function Person(name) {
this.name = name;
}
// 2. prototype 是一个对象,包含 constructor 属性
console.log(Person.prototype); // { constructor: f Person() }
// 3. 实例通过 __proto__ 访问原型
const john = new Person("John");
console.log(john.__proto__ === Person.prototype); // true
// 4. 原型链查找
Person.prototype.sayHello = function () {
return `Hello, I'm ${this.name}`;
};
console.log(john.sayHello()); // "Hello, I'm John"
console.log(john.toString()); // [object Object] - 来自 Object.prototype
// 5. 原型链的尽头
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
john (实例)
↓ __proto__
Person.prototype
↓ __proto__
Object.prototype
↓ __proto__
null
// 父类
function Animal(name) {
this.name = name;
this.colors = ["black", "white"];
}
Animal.prototype.sayName = function () {
console.log(`My name is ${this.name}`);
};
// 子类
function Dog(name, breed) {
this.name = name;
this.breed = breed;
}
// 原型链继承
Dog.prototype = new Animal(); // 问题1:无法给父类构造函数传参
Dog.prototype.constructor = Dog; // 修正 constructor 指向
Dog.prototype.bark = function () {
console.log(`${this.name} is barking!`);
};
// 测试
const dog1 = new Dog("Max", "Golden Retriever");
dog1.sayName(); // "My name is Max"
dog1.bark(); // "Max is barking!"
// 问题2:引用类型属性共享
const dog2 = new Dog("Buddy", "Poodle");
dog1.colors.push("brown");
console.log(dog2.colors); // ['black', 'white', 'brown'] - 被污染了!
function Animal(name) {
this.name = name;
this.colors = ["black", "white"];
}
function Dog(name, breed) {
// 借用父类构造函数
Animal.call(this, name); // 关键!
this.breed = breed;
}
const dog1 = new Dog("Max", "Golden");
const dog2 = new Dog("Buddy", "Poodle");
dog1.colors.push("brown");
console.log(dog1.colors); // ['black', 'white', 'brown']
console.log(dog2.colors); // ['black', 'white'] - 独立了!
// 缺点:无法继承父类原型上的方法
// Animal.prototype.sayName 无法被 Dog 实例访问
function Animal(name) {
this.name = name;
this.colors = ["black", "white"];
}
Animal.prototype.sayName = function () {
console.log(`My name is ${this.name}`);
};
function Dog(name, breed) {
// 1. 借用构造函数继承属性
Animal.call(this, name);
this.breed = breed;
}
// 2. 原型链继承方法
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function () {
console.log(`${this.name} is barking!`);
};
// 测试
const dog1 = new Dog("Max", "Golden");
const dog2 = new Dog("Buddy", "Poodle");
dog1.sayName(); // "My name is Max"
dog1.bark(); // "Max is barking!"
dog1.colors.push("brown");
console.log(dog2.colors); // ['black', 'white'] - 独立
// 问题:调用了两次父类构造函数
// 1. Dog.prototype = new Animal()
// 2. Animal.call(this, name)
// Object.create() 的实现原理
function objectCreate(o) {
function F() {}
F.prototype = o;
return new F();
}
// 使用示例
const animal = {
name: "Animal",
colors: ["black", "white"],
sayName: function () {
console.log(`My name is ${this.name}`);
},
};
const dog = objectCreate(animal);
dog.name = "Max";
dog.bark = function () {
console.log("Woof!");
};
dog.sayName(); // "My name is Max"
dog.bark(); // "Woof!"
// 引用类型属性共享问题依然存在
const cat = objectCreate(animal);
dog.colors.push("brown");
console.log(cat.colors); // ['black', 'white', 'brown']
function createDog(original) {
const clone = Object.create(original);
// 增强对象
clone.bark = function () {
console.log("Woof!");
};
clone.name = "Max";
return clone;
}
const animal = {
colors: ["black", "white"],
sayName: function () {
console.log(`My name is ${this.name}`);
},
};
const dog = createDog(animal);
dog.sayName(); // "My name is Max"
dog.bark(); // "Woof!"
// 关键函数:继承原型
function inheritPrototype(subType, superType) {
// 创建父类原型的副本
const prototype = Object.create(superType.prototype);
// 修正 constructor 指向
prototype.constructor = subType;
// 设置子类原型
subType.prototype = prototype;
}
// 父类
function Animal(name) {
this.name = name;
this.colors = ["black", "white"];
}
Animal.prototype.sayName = function () {
console.log(`My name is ${this.name}`);
};
// 子类
function Dog(name, breed) {
// 继承属性
Animal.call(this, name);
this.breed = breed;
}
// 继承原型(关键步骤)
inheritPrototype(Dog, Animal);
// 添加子类方法
Dog.prototype.bark = function () {
console.log(`${this.name} is barking!`);
};
// 测试
const dog1 = new Dog("Max", "Golden");
const dog2 = new Dog("Buddy", "Poodle");
dog1.sayName(); // "My name is Max"
dog1.bark(); // "Max is barking!"
dog1.colors.push("brown");
console.log(dog2.colors); // ['black', 'white']
// 优点:
// 1. 只调用一次父类构造函数
// 2. 原型链保持不变
// 3. 能够正常使用 instanceof 和 isPrototypeOf
console.log(dog1 instanceof Dog); // true
console.log(dog1 instanceof Animal); // true
console.log(dog1 instanceof Object); // true
class Animal {
constructor(name) {
this.name = name;
this.colors = ["black", "white"];
}
sayName() {
console.log(`My name is ${this.name}`);
}
// 静态方法
static isAnimal(obj) {
return obj instanceof Animal;
}
// Getter/Setter
get description() {
return `${this.name} the animal`;
}
set description(value) {
console.log("Cannot set description directly");
}
}
class Dog extends Animal {
constructor(name, breed) {
// 必须调用 super()
super(name);
this.breed = breed;
}
// 方法重写
sayName() {
console.log(`${this.name} says: Woof!`);
}
// 新增方法
bark() {
console.log("Woof woof!");
}
// 调用父类方法
sayNameOriginal() {
super.sayName();
}
// 静态方法也可以继承
static isDog(obj) {
return obj instanceof Dog;
}
}
// 使用
const dog = new Dog("Max", "Golden");
dog.sayName(); // "Max says: Woof!"
dog.sayNameOriginal(); // "My name is Max"
dog.bark(); // "Woof woof!"
console.log(dog.description); // "Max the animal"
// 静态方法
console.log(Dog.isAnimal(dog)); // true
console.log(Dog.isDog(dog)); // true
// ES6 Class 继承的 Babel 转译结果
"use strict";
function _inherits(subClass, superClass) {
// 1. 检查 superClass 是否为函数或 null
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
// 2. 继承原型(寄生组合式继承)
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true,
},
});
// 3. 继承静态属性和方法
if (superClass) _setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf =
Object.setPrototypeOf ||
function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _createSuper(Derived) {
var hasNativeReflectConstruct = _isNativeReflectConstruct();
return function _createSuperInternal() {
var Super = _getPrototypeOf(Derived),
result;
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
result = Super.apply(this, arguments);
}
return _possibleConstructorReturn(this, result);
};
}
// 基础 Mixin
const CanSwim = {
swim() {
console.log(`${this.name} is swimming`);
},
};
const CanFly = {
fly() {
console.log(`${this.name} is flying`);
},
};
const CanRun = {
run() {
console.log(`${this.name} is running`);
},
};
// Mixin 辅助函数
function mixin(target, ...sources) {
Object.assign(target, ...sources);
}
// 或更完善的版本
function applyMixins(derivedCtor, baseCtors) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
if (name !== "constructor") {
derivedCtor.prototype[name] = baseCtor.prototype[name];
}
});
});
}
// 使用 Mixin
class Animal {
constructor(name) {
this.name = name;
}
}
class Bird extends Animal {}
// 应用 Mixin
Object.assign(Bird.prototype, CanFly, CanRun);
const eagle = new Bird("Eagle");
eagle.fly(); // "Eagle is flying"
eagle.run(); // "Eagle is running"
const swimming = Symbol("swimming");
const flying = Symbol("flying");
const Swimmer = {
[swimming]() {
console.log(`${this.name} is swimming`);
},
};
const Flyer = {
[flying]() {
console.log(`${this.name} is flying`);
},
};
class Duck {
constructor(name) {
this.name = name;
}
act() {
if (this[swimming]) this[swimming]();
if (this[flying]) this[flying]();
}
}
Object.assign(Duck.prototype, Swimmer, Flyer);
const donald = new Duck("Donald");
donald.act(); // 游泳和飞行
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function () {
console.log(`Hello, I'm ${this.name}`);
};
function Student(name, grade) {
Person.call(this, name);
this.grade = grade;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
const john = new Student("John", "A");
// 1. instanceof
console.log(john instanceof Student); // true
console.log(john instanceof Person); // true
console.log(john instanceof Object); // true
// 2. isPrototypeOf
console.log(Student.prototype.isPrototypeOf(john)); // true
console.log(Person.prototype.isPrototypeOf(john)); // true
console.log(Object.prototype.isPrototypeOf(john)); // true
// 3. getPrototypeOf
console.log(Object.getPrototypeOf(john) === Student.prototype); // true
console.log(Object.getPrototypeOf(Student.prototype) === Person.prototype); // true
// 4. setPrototypeOf (谨慎使用,性能差)
const obj = {};
Object.setPrototypeOf(obj, Array.prototype);
console.log(Array.isArray(obj)); // false (不是真正的数组)
// 5. Object.create
const proto = { x: 10 };
const obj2 = Object.create(proto, {
y: {
value: 20,
writable: true,
enumerable: true,
},
});
console.log(obj2.x); // 10 (从原型继承)
console.log(obj2.y); // 20 (自有属性)
function getAllPrototypes(obj) {
const prototypes = [];
let current = obj;
while ((current = Object.getPrototypeOf(current))) {
prototypes.push(current);
}
return prototypes;
}
class A {}
class B extends A {}
class C extends B {}
const c = new C();
console.log(getAllPrototypes(c));
// [C.prototype, B.prototype, A.prototype, Object.prototype]
// 获取所有属性(包括继承的)
function getAllProperties(obj) {
const properties = new Set();
let current = obj;
do {
Object.getOwnPropertyNames(current).forEach(prop => {
properties.add(prop);
});
} while ((current = Object.getPrototypeOf(current)));
return Array.from(properties);
}
const obj = { a: 1 };
console.log(getAllProperties(obj));
// ['a', 'constructor', '__defineGetter__', '__defineSetter__', ...]
// Vue.js 风格的插件系统
class Vue {
constructor(options) {
this.$options = options;
this.$data = options.data();
}
$emit(event, ...args) {
console.log(`Event ${event} emitted:`, args);
}
}
// 插件 Mixin
const LoggerMixin = {
$log(message) {
console.log(`[LOG]: ${message}`);
},
$error(message) {
console.error(`[ERROR]: ${message}`);
},
};
// Router 插件
class VueRouter {
constructor(routes) {
this.routes = routes;
}
push(path) {
console.log(`Navigating to ${path}`);
}
}
// 使用 Mixin 扩展 Vue
Object.assign(Vue.prototype, LoggerMixin);
// 使用插件
Vue.use = function (plugin) {
if (typeof plugin.install === "function") {
plugin.install(this);
} else if (typeof plugin === "function") {
plugin(this);
}
};
const routerPlugin = {
install(Vue) {
Vue.prototype.$router = new VueRouter([]);
},
};
Vue.use(routerPlugin);
const app = new Vue({ data: () => ({ message: "Hello" }) });
app.$log("App created"); // 来自 Mixin
app.$router.push("/home"); // 来自插件
class AppError extends Error {
constructor(message, code = "APP_ERROR") {
super(message);
this.name = this.constructor.name;
this.code = code;
this.timestamp = new Date();
// 保持正确的堆栈跟踪
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
toJSON() {
return {
name: this.name,
message: this.message,
code: this.code,
timestamp: this.timestamp,
stack: this.stack,
};
}
}
class ValidationError extends AppError {
constructor(field, message) {
super(`Validation failed for ${field}: ${message}`, "VALIDATION_ERROR");
this.field = field;
}
}
class NetworkError extends AppError {
constructor(url, status) {
super(`Network request to ${url} failed with status ${status}`, "NETWORK_ERROR");
this.url = url;
this.status = status;
}
}
// 使用
try {
throw new ValidationError("email", "Invalid email format");
} catch (error) {
if (error instanceof ValidationError) {
console.error("Validation error:", error.toJSON());
} else if (error instanceof NetworkError) {
console.error("Network error:", error.toJSON());
}
console.log(error instanceof AppError); // true
console.log(error instanceof Error); // true
}
// 原型链越长,属性查找越慢
class Level1 {}
class Level2 extends Level1 {}
class Level3 extends Level2 {}
// ... 继承很多层
const obj = new Level10();
// 优化:缓存频繁访问的属性
class Optimized {
constructor() {
// 将常用方法复制到实例上
this.frequentlyUsedMethod = this.frequentlyUsedMethod.bind(this);
}
frequentlyUsedMethod() {
// 频繁调用的方法
}
}
// ❌ 不好的做法:污染全局原型
Array.prototype.myCustomMethod = function () {
// ...
};
// ✅ 好的做法:使用组合或子类
class MyArray extends Array {
myCustomMethod() {
// ...
return this;
}
}
// ✅ 或者使用工具函数
function arrayUtils(arr) {
return {
customMethod: function () {
// 操作 arr
return arr;
},
};
}
// instanceof 的问题
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const iframeArray = iframe.contentWindow.Array;
const arr = new iframeArray(1, 2, 3);
console.log(arr instanceof Array); // false(不同的全局对象)
console.log(Array.isArray(arr)); // true
// Symbol.hasInstance 自定义 instanceof 行为
class MyClass {
static [Symbol.hasInstance](../04-javascript/instance) {
return instance && instance.isMyClass;
}
}
const obj = { isMyClass: true };
console.log(obj instanceof MyClass); // true
__proto__,使用 Object.getPrototypeOfObject.setPrototypeOf(性能差)Object.create(null) 创建纯字典对象Array.isArray 而不是 instanceof ArraySymbol.hasInstance 自定义检查Object.prototype.toString.call() 进行类型判断