每个实例对象(object)都有一个私有属性(__proto__)指向其构造函数的原型对象(prototype)。该原型对象也有自己的原型对象,层层向上直到一个对象的原型对象为null。根据定义null没有原型,并作为原型链的最后一个环节。
几乎所有JS中的对象都是位于原型链顶端的Object的实例
基于原型链的继承
继承属性
JS对象有一个指向原型对象的链。当试图访问一个对象的属性时,还会搜索该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或者到达原型链的末尾。
tips: 遵循ECMAScript标准,someObject.[[prototype]]符号用于访问someObject的原型,等同于JS的非标准但许多浏览器实现的属性__proto__。
但是不能与构造函数func的prototype属性相混淆。被构造函数创建的实例对象的[[prototype]]指向func的prototype属性。Object.prototype属性表示Object的原型对象。
let f=function(){
this.a = 1;
this.b = 2;
}
let o = new f();
// 在f函数的原型上定义属性
f.prototype.b = 3;
f.prototype.c = 4;
// 不要在f的原型上直接定义f.prototype = {b:3,c:4};这样会直接破坏原型链
// o.[[prototype]] 有属性b和c
// (其实这就是o.__proto__ 或者 o.constructor.prototype)
// o.[[prototype]].[[prototype]]是Object.prototype
// 最后o.[[prototype]].[[prototype]].[[prototype]]是null
// 这就是原型链的末尾,即null
// 根据定义,null就是没有[[prototype]]
// 综上,这个原型链如下:
// {a:1, b:2}--->{b:3, c:4}---> Object.prototype ---> null
console.log(o.a); // 1
// a是o的自身属性吗?是的,该属性的值是1
console.log(o.b); // 2
// b是o的自身属性吗?是的,该属性值为2
// 原型上也有一个‘b’属性,但是它不会被访问到
// 这种情况叫做“属性遮蔽”
console.log(o.c) // 4
// c是o的自身属性吗?不是,那看看它的原型上有没有
// c是o.[[prototype]]的属性吗?是,该属性值为4
console.log(o.d) // undefined
// d是o的自身属性吗?不是,那看看它的原型上有没有
// d是o.[[prototype]]的属性吗?不是,那看看他的原型上有没有
// o.[[prototype]].[[prototype]]为null,停止搜索
// 找不到d属性返回undefined
使用不同的方法来创建对象和生成原型链
(1)使用语法结构创建的对象
var o = {a: 1};
// o这个对象继承了Object.prototype上面的所有属性
// Object.prototype的原型为null
// 原型链如下
// o -->Object.prototype -->null
var a = ["yo", "dkdkk", "dkl"];
// 数组都继承自 Array.prototype
// 原型链如下
// a --> Array.prototype --> Object.prototype --> null
function f(){
return 2;
}
// 函数都继承自Function.prototype
// 原型链如下
// f --> Function.prototype --> Object.prototype --> null
(2)使用构造器创建的对象
在JS中,构造器其实就是一个普通的函数,当使用new 操作符来调用这个函数时,他就可以被称为构造方法(构造函数)。
function Graph(){
this.vertices = [];
this.edges = [];
}
Graph.prototype = {
addVertex:function(v){
this.vertices.push(v)
}
}
var g = new Graph();
// g是生成的对象,他的自身属性有‘vertices’和edges
// 在g被实例化时,g.[[prototype]]指向了Graph.prototype
(3)使用Object.create创建的对象
可以调用Object.create()创建一个对象,新对象的原型就是传入的第一个参数。
var a = {a:1};
// a --> Object.prototype --> null
var b = Object.create(a);
// b --> a --> Object.prototype --> null
var c = Object.create(b)
// c --> b --> a -->Object.prototype --> null
var d = Object.create(null);
// d --> null
console.log(d.hasOwnProperty);
// undefined ,因为d没有继承Object.prototype
(4)使用Class关键字创建的对象
class Polugon{
constructor(height, width){
this.height = height;
this.width = width;
}
}
class Square extends Polygon{
constructor(sideLength){
super(sideLength, sideLength)
}
get area(){
return this.height * this.width
}
set sideLength(newLength){
this.height = newLength;
this.width = newLength;
}
}
var square = new Square()
每张故作坚强的笑脸背后,是怎样风雨漂泊的一生---Lin