每个实例对象(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
本文分享自微信公众号 - 女程序员的日常(gh_df41d619fb70),作者:凛
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2020-03-03
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句