JavaScript面试考点之原型及原型链

1、JavaScript原型及原型链

1)原型

JavaScript是一种基于原型的语言,即每一个对象拥有一个原型对象。当我们试图去访问一个对象的属性时,不仅在该对象去搜寻,还会去对象的原型,以及该对象原型的原型,依次层层想上搜索,直到找到或到达原型链末尾。

这些属性和方法定义在Object的构造器函数的prototype属性上,而非实例本身。

函数可以有属性。每个函数都有一个特殊的属性叫作原型prototype。

a、每一个函数数据类型(普通函数、类)都有一个自带属性:prototype(原型),并且这个属性是一个对象数据类型的值。

b、并且在prototype上浏览器给它加上了一个属性constructor(构造函数),属性值时当前函数(类)本身;

c、每一个对象数据类型(普通对象、实例、prototype)也自带一个属性__proto__,属性值是当前实例所属类的原型(prototype)。

原型对象有一个自有属性constructor,这个属性指向该函数。关系图如下:

2)原型链

当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。

构造函数Person存在原型对象是Person.prototype;

构造函数生成实例对象person,person的__proto__指向构造函数Person原型对象;

Person.prototype.__proto__ 指向内置对象,因为 Person.prototype 是个对象,默认是由 Object函数作为类创建的,而 Object.prototype 为内置对象;

Person.__proto__指向内置匿名函数anonymous,因为 Person 是个函数对象,默认由 Function 作为类创建。

Function.prototype和Function.__proto__同时指向内置匿名函数anonymous,这样原型链的终点就是null。

总结:

__proto__和prototype关系:__proto__和constructor是对象独有的。prototype属性是函数独有的

__proto__作为不同对象之间的桥梁,用来指向创建它的构造函数的原型对象的。

每个对象的__proto__都是指向它的构造函数的原型对象prototype的;

构造函数是一个函数对象,是通过 Function构造器产生的;

原型对象本身是一个普通对象,而普通对象的构造函数都是Object;

所有的构造器都是函数对象,函数对象都是 Function构造产生的;

Object的原型对象也有__proto__属性指向null,null是原型链的顶端。

a、一切对象都是继承自Object对象,Object 对象直接继承根源对象null

b、一切的函数对象(包括 Object 对象),都是继承自 Function 对象

c、Object 对象直接继承自 Function 对象

d、Function对象的__proto__会指向自己的原型对象,最终还是继承自Object对象

实例.__proto__ === 原型

原型.constructor === 构造函数

构造函数.prototype === 原型

js 获取原型的方法:

p.proto

p.constructor.prototype

Object.getPrototypeOf(p)

思考:Number.prototype.constructor === Number.constructor 结果相等吗?

答案是不相等。因为Number.prototype.constructor 查找的是自己 Number 原型上的构造函数。Number是没有有 constructor 属性,就会原型链的 __proto__ 向上查找上一级类(这里是函数)的原型,函数的 constructor 指向 Function。所以不同。

2、判断属性是否继承自原型链

JavaScript中Object对象原型上的hasOwnProperty()用来判断一个属性是定义在对象本身而不是继承自原型链。

因为JavaScript没有将hasOwnProperty作为一个敏感词,所以我们很有可能将对象的一个属性命名为hasOwnProperty,这样一来就无法再使用对象原型的 hasOwnProperty 方法来判断属性是否是来自原型链。

则我们需要使用原型链上真正的 hasOwnProperty 方法

3、属性遍历方法

Object.keys() 方法会返回一个由给定对象的所有可枚举自身属性的属性名组成的数组,不包括继承自原型的属性和不可枚举的属性。

Reflect.ownKeys()返回所有自有属性key,不管是否可枚举,但不包括继承自原型的属性

for in主要用于遍历对象的可枚举属性包括自有属性、继承自原型的属性

Object.assign()          //会忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

使用Object.defineProperty()方法设置enumerable,Object.defineProperty(obj, prop, descriptor)方法有三个参数

obj:目标对象

prop:目标属性,字符串

descriptor:对目标属性的行为,放在对象里

enumerable为true时表示可枚举,enumerable为false表示不可枚举;

每个对象都有propertyIsEnumerable()方法,这个方法可以判断出指定的属性是否可枚举。propertyIsEnumerable方法只对对象自身的属性(对象自身添加的、构造函数实例化的)有效,对原型上的、继承来的属性都无效。

obj.propertyIsEnumerable("属性名");

1)这个属性必须属于实例的,并且不属于原型。

2)这个属性必须是可枚举的。

3)如果对象没有指定的属性,该方法返回false

4、对new的理解

new操作符用于创建一个给定构造函数的实例对象。

new的流程:

a、创建一个新的对象obj;

b、将对象与构建函数通过原型链连接起来;

c、将构建函数中的this绑定到新建的对象obj上;

d、根据构建函数返回类型作判断,如果是原始值则被忽略,如果是返回对象,需要正常处理。(new 关键词执行之后总是会返回一个对象,要么是实例对象,要么是 return 语句指定的对象

当构造函数最后return出来的是一个和this无关的对象时,new 命令会直接返回这个新对象,而不是通过 new 执行步骤生成的 this 对象。

但是这里要求构造函数必须是返回一个对象,如果返回的不是对象,那么还是会按照 new 的实现步骤,返回新生成的对象。

手写new

a、使用Object.create将obj 的proto指向为构造函数的原型;

b、使用apply方法,将构造函数内的this指向为obj;

c、在create返回时,使用三目运算符决定返回结果。

构造函数如果有显式返回值,且返回值为对象类型,那么构造函数返回结果不再是目标实例

5、继承

1)原型继承

直接让子类的原型对象指向父类实例,当子类实例找不到对应的属性和方法时,就会往它的原型对象,也就是父类实例上找,从而实现对父类的属性和方法的继承。

缺点:它是通过链式继承的,属于引用类型传值,不是复制一份,引用副本实例属性的修改必然会引起其他副本实例属性的修改。

2)call继承(构造函数继承)

构造函数继承,即在子类的构造函数中执行父类的构造函数,并为其绑定子类的this,让父类的构造函数把成员属性和方法都挂到子类的this上去,这样既能避免实例之间共享一个原型实例,又能向父类构造方法传参。

复制一份,子类的实例各自得到一份构造函数的副本,属于值传递,所以子类之间的属性修改是互不相关的,跟父类就没有关系了。

缺点:继承不到父类原型上的属性和方法。

3)组合式继承

原型继承+call继承。在子类的构造函数中通过Parent.call(this)继承父类的属性,然后改变子类的原型为new Parent()来继承父类的函数。

缺点:每次创建子类实例都执行了两次构造函数(Parent.call()和new Parent()),虽然这并不影响对父类的继承,但子类创建实例时,原型中会存在两份相同的属性和方法

4)寄生组合式继承

为了解决每次创建子类实例都执行了两次构造函数的问题,私有的只拿私有的,用call来做。共有只拿共有的,用Object.create()来做。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容