来一段 类式继承(classical inheritance)的代码
//父类
function User(username) {
this.username = username ? username : "Unknown";
this.books = ["coffe", "1891"];
User.prototype.read = function () {
console.log(this.username + '喜欢读的书是:' + this.books.join("/"));
}
}
//子类
function CoffeUser(username) {
if (username)
this.username = username;
}
//关键
CoffeUser.prototype = new User();
const user1 = new CoffeUser("bob");
const user2 = new CoffeUser("steve");
//instanceof是检测某个对象是否是某个类的实例
console.log(user1 instanceof User); //>> true
// 可访问原型链上的属性
console.log(user1.books); //>> ["coffe", "1891"]
// 可访问原型链上的方法
user1.read();//>> bob喜欢读的书是:coffe/1891
user2.read();//>> steve喜欢读的书是:coffe/1891
//修改来自原型上的引用类型的属性,则有副作用:会影响到所有实例
user1.books.push("hello");
console.log(user1.books); //>> ["coffe", "1891", "hello"]
console.log(user2.books); //>> ["coffe", "1891", "hello"]
//修改来自原型上的值类型的属性,无副作用
user1.username = 'bill';
console.log(user1.username, user2.username); //>> bill steve缺陷
引用类型属性的误修改,原型属性中的引用类型属性会被所有实例共享,若子类实例更改从父类原型继承来的引用类型的共有属性,会影响其他子类。
为什么会这样?
因为引用类型一般比值类型复杂,引用类型存储在内存的Heap(堆)区,值类型存储在内存的Stack(栈)区。传递参数的时候,针对引用类型仅仅传递的是一个指针而已,而针对值类型会传一个copy副本。所以本例中修改一个引用类型的属性,一定会影响到其他子类。反之可以这样思考:如果一个引用类型也传递的是copy,恰好该引用类型的对象超级复杂、所占内存超级多(比如大型3D游戏的场景对象),那么计算机的内存很快被耗尽,干不了其他事情,这将会是灾难。