在写程序时,我们经常会想要拓展一些东西。
例如我们有一个user object,他有自己的属性跟函数,我们希望将admin与guest基於user稍作修改,重用user中的内容,并不是复制,只是在user上建构一个新的对象。
原型继承(Prototypal inheritance)这个语言特性能帮助我们实现这个需求。
在JavaScript中,对象有一个特殊的隐藏属性,不是null就是对另一个Object的引用,该对像称为原型。
当我们从object读取一个不存在的属性时,JavaScript会自动从原型中找寻获取该属性,这就是原型继承。[[prototype]]是隐藏的,但有另一个属性可以获取到原型 :
let animal = {
eats: true
};
let cat = {
jumps: true
};
cat.__proto__ = animal; // 设置 rabbit.[[Prototype]] = animal
// 现在这两个属性我们都能在 cat 中找到:
console.log( cat.eats ); // true
console.log( cat.jumps ); // true
如果animal中有个函数,他一样可以在cat中取用 :
let animal = {
eats: true,
walk() {
alert("Animal walk");
}
};
let cat = {
jumps: true,
__proto__: animal
};
// walk 方法是从原型中获得/继承的
rabbit.walk(); // Animal walk
原型链可以很长 :
let animal = {
eats: true,
walk() {
alert("Animal walk");
}
};
let cat = {
jumps: true,
__proto__: animal
};
let foldEar = {
earLength: 2,
__proto__: cat
};
// walk 一样透过原型链取得
longEar.walk(); // Animal walk
alert(foldEar.jumps); // true (继承cat)
这里有两个限制
当然只能有一个[[prototype]]。
__proto__是[[prototype]]的历史原因而留下来的getter/setter
这两个是不一样的,__prototype__是[[prototype]]的getter/setter。
__proto__属性有点过时了,他的出现是因为历史原因。现代编程建议我们使用函数Object.getPrototypeof/Object.setPrototypeOf来取代__prototype__去get/set原型。
原型只用於读取属性,如果要写入或删除属性直接在object中操作。
在下面的例子我们将cat分配自己的walk :
let animal = {
eats: true,
walk() {
alert("Animal walk");
}
};
let cat = {
__proto__: animal
};
cat.walk = function() {
console.log("cat walk!");
};
cat.walk(); // cat walk!
访问器(accessor)是一个例外,因为assignment操作是由setter函数处里的。因此,写入此类型属性时实际上跟调用函数相同。
参考以下代码 :
let user = {
name: "John",
surname: "Smith",
set fullName(value) {
[this.name, this.surname] = value.split(" ");
},
get fullName() {
return `${this.name} ${this.surname}`;
}
};
let admin = {
__proto__: user,
isAdmin: true
};
alert(admin.fullName); // John Smith
// setter 作用
admin.fullName = "Alice Cooper"; // 在admin object中新增name与surname
alert(admin.fullName); // Alice Cooper,admin 的内容被修改了
alert(user.fullName); // John Smith,user 的内容被保护了
for..in回圈也会把继承的属性算入 :
let animal = {
eats: true
};
let cat = {
jumps: true,
__proto__: animal
};
// Object.keys 只返回自己的属性
console.log(Object.keys(cat)); // jumps
// for..in 会遍历自己以及继承的属性
for(let prop in cat) console.log(prop); // jumps,eats
如果只是要object本身的属性,并不想要继承的属性,那可以使用内建方法obj.hasOwnProperty(key) :
let animal = {
eats: true
};
let cat = {
jumps: true,
__proto__: animal
};
for(let prop in cat) {
let isOwn = cat.hasOwnProperty(prop);
if (isOwn) {
console.log(`Our: ${prop}`); // Our: jumps
} else {
console.log(`Inherited: ${prop}`); // Inherited: eats
}
}
cat从animal中继承,animal从Object.prototype中继承(默认继承),然後像上是null。
那cat.hasOwnProperty方法从哪来的? 图中可以看到是Object.prototype.hasOwnProperty提供的,换句话说是继承的,那为什麽for..in回圈并没有像eat和jumps那样出现在回圈中呢?
Ans: 因为它是不可枚举的。就像object.prototype的其他属性,hasOwnProperty有enumerable:false标志。并且for...in只会列出可枚举的属性。
>>: 110/11 - 把照片储存在Pictures/应用程序名称资料夹 - 1
在探讨这个问题之前,先来分享我们目前的销售流程 搜集名单 透过脸书投放名单型广告,或是 Google...
已经打包拿到客户那的 Electron 应用程序 , 如果有 BUG 需要更新时该怎麽办呢 ? 一般...
前言:在第11天的时候我们有讨论到伫列,今天就是来把之前的坑给补上的,先前没有提到的就是等等要介绍的...
字串 函数应用方法 len() – 字串长度 min() – 最小值 max() – 最大值 使用...
昨天介绍了一些名词,今天继续提Node.js Node.js一点入门 今天直接贴上程序码,再去做解释...