javascript-原型、原型链深入理解

通过阅读本文你会了解到什么是:原型和原型链、普通对象和函数对象、__proto__prototype、构造函数(constructor)

1、普通对象和函数对象

在javascript中万物皆对象,对象分为普通对象和函数对象,可以通过typeof来判断对象是哪一种类型的对象。

1.1 普通对象

typeof obj === 'object'; // true

let obj1 = {};
let obj2 = new Object();
let obj3 = new Array();

console.log(typeof obj1); // object
console.log(typeof obj2); // object
console.log(typeof obj3); // object

1.2 函数对象

typeof obj === 'function'; // true

let f1 = new Function('a', 'b', 'return a + b');
let f2 = function () {};
function f3() {};

console.log(typeof f1); // function
console.log(typeof f2); // function
console.log(typeof f3); // function

console.log(typeof Function); // function
console.log(typeof Object); // function
console.log(typeof Array); // function

console.log(Function.constructor === Function); // true
console.log(Object.constructor === Function); // true
console.log(Array.constructor === Function); // true

注: 凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,f3,实际上也是要通过 new Function()的方式进行创建。Function Object 也是通过 New Function()创建的。javascript大部分内置对象的构造器属于函数对象

2、构造函数

构造函数是用来初始化新创建的对象的,属于函数对象。

(1)使用构造函数创建两个实例

function Student(name, age) {
    this.name = name;
    this.age = age;
}

let student1 = new Student('Ada', 23);
let student2 = new Student('Bob', 25);
console.log(student1.name, student1.age); // Ada 23
console.log(student2.name, student2.age); // Bob 25
console.log(typeof Student); // function

如果使用构造函数来初始化新创建的对象,记得用new关键字。

(2)错误示范:如果不用new关键字,那么this就会指向当前调用该构造函数的对象,本例中是window

let student3 = Student('Sunny', 23);
console.log(student3); // undefined
console.log(window.name, window.age); // Sunny 23

(3)构造函数创建的实例和构造函数间的关系

console.log(student1.constructor === Student); // true
console.log(student2.constructor === Student); // true

注: 用构造函数创建的实例都具有constructor属性,该属性指向其构造函数。实例.constructor === 构造函数

3、原型(原型对象)- prototype

  • 原型是一个对象(也被称为原型对象),是类的核心,可以通过原型实现原型(对象)的属性继承。
  • 某些对象有些预定义的属性,其中函数对象有一个prototype对象,指向其原型对象

(1)创建两个Student实例

function Student(name, age) {
    this.name = name;
    this.age = age;
}
Student.prototype.sayHello = function () {
    console.log(`hello ${this.School}, my name is ${this.name}.`);
};
Student.prototype.School = 'CUIT';

let student1 = new Student('Ada', 23);
let student2 = new Student('Bob', 25);
student1.sayHello(); // hello CUIT, my name is Ada.
student2.sayHello(); // hello CUIT, my name is Bob.

console.log(student1.prototype); // undefined

通过对构造函数的原型对象的属性赋值,可以让所有的实例都具有构造函数.prototype中的所有属性。其属性值中的this指代当前实例对象(最好不要用箭头函数来书写函数,不然this的指代不同)。
所以: prototype属性只有函数对象才有。

(2)Student.prototype


Student.prototype
console.log(Student.prototype.constructor === Student); // true

原型对象具有constructor属性,指向prototype属性所在的函数(构造函数)。上文我们有推断实例.constructor === 构造函数,所以我们可以仅仅认为(Student.prototype instanceof Student ; // false构造函数.prototype是构造函数的一个实例。

(3)特殊的Function.prototype

一般情况下我们可以认为原型对象是一个普通对象,但是Function.prototype是一个函数对象。我们上文提到过凡是通过 new Function() 创建的对象都是函数对象,且我们可以认为构造函数.prototype是构造函数的一个实例,所以Function.prototype就是一个函数对象

Function.prototype

4、_proto_

javascript在创建对象时候,都有一个叫做__proto__的内置属性,用于指向创建它的构造函数的原型对象。但是__proto__并不是一个规范的属性,只有部分浏览器(比如:Firefox和Chrome)才支持。

console.log(student1.__proto__ === Student.prototype); // true

实例.__proto__ === 构造函数t.prototype; // true

《JavaScript 高级程序设计》的图 6-1---是"==="的关系

(1)实例的_proto_和构造函数及其原型间的关系

function testProto(factory) {
    let obj = new factory();
    console.log(obj.constructor === factory);
    console.log(obj.__proto__ === factory.prototype);
}

testProto(Array); // true true
testProto(Date); // true true
testProto(Function); // true true

(2)javascrpt部分内置构造器和Function间的关系

console.log(Date.constructor === Function); // true
console.log(Date instanceof Function); // true
console.log(Date.__proto__ === Function.prototype); // true

console.log(Object.constructor === Function); // true
console.log(Object instanceof Function); // true
console.log(Object.__proto__ === Function.prototype); // true

console.log(Function.constructor === Function); // true
console.log(Function instanceof Function); // true
console.log(Function.__proto__ === Function.prototype); // true

所有函数对象的proto都指向Function.prototype,它是一个空函数(Empty function),但是其原型对象有一些内置的属性:如length、call、apply、bind等

(3)Function.prototype.__proto__

console.log(Function.prototype.__proto__ === Object.prototype); // true

这说明所有的构造器也都是一个普通对象,所以可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。

(4)Object.prototype.__proto__

console.log(null === Object.prototype.__proto__ ); // true

5、原型链

原型链,由原型对象组成的链式关系。因为每个对象都有原型,原型也是对象,也具有原型,这样一层一层往上链接,最后就构成了原型链。原型链最顶端(Object.prototype.__proto__)指向null。原型链的形成真正是靠_proto_ 而非prototype

6、总结

函数对象才有prototype(实例共享属性和方法)属性,对象都有__proto__(指向该对象构造函数的原型)属性

  • 构造函数.prototype == 构造函数.prototype
  • 构造函数.prototype.constructor == 构造函数
  • 函数对象.__proto__ == Function.prototype
  • 构造函数.__proto__ == Function.prototype
  • 实例.__proto__ == 构造函数.prototype
  • 实例.constructor == 构造函数
  • typeof Function.prototype // function
  • Function.__proto__ == Function.prototype
  • Function.constructor == Function
  • Function.prototype.__proto__ == Object.prototype
  • Object.prototype.__proto__ == null
    原型链

6、小练习

(1) new Foo().__proto__
(2) Foo.__proto__
(3) Foo.prototype.__proto__
(4) Object.__proto__

7、友情链接

注:本文内容是看了Yi罐可乐-最详尽的 JS 原型与原型链终极详解3系列总结出来的。

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

推荐阅读更多精彩内容

  • JS中原型链,说简单也简单。 首先明确: 函数(Function)才有prototype属性,对象(除Object...
    前小白阅读 3,913评论 0 9
  • 原型链是一种机制,指的是 JavaScript 每个对象都有一个内置的 __proto__ 属性指向创建它的构造函...
    劼哥stone阅读 4,405评论 15 80
  • 理解 javascript 的原型链及继承 以上所有的运行结果都是 true; 三种构造对象的方法: 通过对象字面...
    你期待的花开阅读 1,505评论 0 3
  • 自满和渴求两个瓶子 在知识老人面前 表现略有差别 渴求伸手要知识 他觉得学无止境 自满堵住瓶口不理知识 知识对他无...
    旖旎i阅读 456评论 3 8
  • 1,本群是严肃的班级家校沟通平台, 发布班级动态、各种通知、保存有价值的照片等。 本群拒绝任何搞笑视频、信息。 本...
    贤齐睿爹阅读 11,203评论 0 1