前端的那些事(六):原型与原型链(精选篇)

前言

首先广为所知的“万物皆对象”是错误的。
简单基本类型string,number,boolean,null,undefined)不是对象。
复杂基本类型object)才是对象;但是object有九个内置对象(String ,Number, Boolean,Object,Function, Array,Date, RegExp,Error

举个例子:

var num1 = 123;
typeof num1; // "Number"
num1 instanceof Number; // false

var num2 = new Number(123);
typeof num2; // "object"
num2 instanceof Number; // true

其实num1这种字面量形式,获取长度,访问值其实是不生效的。但是js引擎自动帮我们转成Number这种形式了。如num1.length

我们这里简单介绍了,不做深入探讨,毕竟js引擎帮我们做了,记住一句话,Object是所有对象的基类

接下来用最通俗易懂的方式给大家解释各种学术名称的原理:
一、__proto__(指针)

Firefox和Chrome 提供__proto__访问器,ECMA标准是[[Prototype]],它是对象内置属性无法访问,可以通过Object.getPrototypeOf()标准方法访问该属性。

从最简单代码开始:

var obj = {};
console.log(obj);

打印的样子:

image.png

只要是对象都有__proto__属性,最底层的constructorObject,也印证了我那句Object是所有对象的基类

二、prototype(原型)

定义

其中每个函数对象都有一个prototype 属性,这个属性指向函数的原型对象。

__proto__区别:

1:每个对象都有 __proto__ 属性,但只有函数对象才有 prototype 属性。
2: __proto__指向的是当前对象的原型对象,而prototype指向的,是以当前函数作为构造函数构造出来的对象的原型对象。

function Foo() {
  var name = '小米';
}
Foo.prototype.sayHello = function() {
  console.log('hello 靓仔');
};
console.log(Foo.prototype);

image.png

大家可以看到Foo.prototype有了sayHello的函数,自然可以调用。这里有两个问题?

  1. sayHello方法想获取Foo函数中的name怎么办?
  2. 图中constructor的prototype里面也有sayHello函数是怎么回事?
2.1 解答问题1

这就是我们为何使用new进行构造函数的原因,因为它有共用属性,函数共使用,还能继承。

function Foo() {
  this.name = '小明';
}
Foo.prototype.sayHello = function() {
  console.log('hello' + this.name);
};

// var obj = {};
// obj.__proto__ = Foo.prototype;
// Foo.call(obj);
// var f = obj;
var f = new Foo();
console.log(f.sayHello());

这里解释两件事情:(大厂面试必问)

  • new是什么,就是我注释掉的代码。
  • 为何用prototype创建函数sayHello,为了避免每一次new Foo()就创建一次sayHello,占用内存,消耗性能。
2.2 解答问题2

直接引出constructor。

三、constructor(构造函数)

function Foo() {
  // ...
}
console.log(Foo.prototype.constructor === Foo); // true

从中可以看出constructor是函数Foo的prototype内置属性,指向函数本身。就是这么简单。

继续看代码:

function Foo() {
  // ...
}
var a = new Foo();
console.log(a.constructor === Foo); // true

是不是说明构造函数a的constructor指向Foo,答案是否定的。

继续改代码

function Foo() {
  // ...
}
Foo.prototype.constructor = {}
var a = new Foo();
console.log(a.constructor === Foo); // false

原因很简单,就是Foo.prototype的constructor被我们设置为{}了,也就是说a.constructor是{}了,说明这个constructor不安全,在某些情况,我们得让它恢复,所以你会看到如下代码:

function Person() {}
Person.prototype = {
  constructor: Person, //这里指向Person,就不会丢失了
  name: '欣雨',
  age: 19,
  sayName: function() {
    console.log(this.name + '年龄' + this.age);
  },
};
// console.log(Person.prototype);
var p = new Person();
p.sayName(); // 欣雨年龄19

constructor介绍完了,我们来解释一下2.2的问题吧,上述注释代码的console.log(Person.prototype)打开,打印一下看看:

image.png

只要你通过原型prototype创建属性和方法时,那么Person.prototypeconstructor下就会有prototype属性包含你创建的。(这里不是很重要,知道就好)

就是我在介绍2prototype(原型)所说:__proto__指向的是当前对象的原型对象,而prototype指向的,是以当前函数作为构造函数构造出来的对象的原型对象。

四、原型链

定义:

原型链就是通过proto属性从当前对象开始查找它的原型对象(通过prototype生成的),一直查找到null为止。

function Person() {}
Person.prototype = {
  constructor: Person, //这里指向Person,就不会丢失了
  name: '欣雨',
  age: 19,
  sayName: function() {
    console.log(this.name + '年龄' + this.age);
  },
};
var p = new Person();
console.log(p);

打印的p下面就是空对象,而需要的属性在proto下面。

类型:
默认的原型链结构就是:当前对象 -> 构造函数.prototype -> Object.prototype -> null
继承改变默认原型链结构,其实通过_proto查找即可。

五、函数的构造函数Function

普通函数:

function foo(num) {
  console.log(num);
}
foo(2);  // 2

构造函数:

var foo = new Function('num', 'console.log( num )');
foo(2);  // 2

好处就是:
Function是使用字符串构建函数,那么就可以在程序运行过程中构建函数。
以前的函数必须一开始就写好,再经过预解析,一步一步的运行。

写一些底层代码,为了性能可以使用。

六 instanceof 原理

A instanceof B 的原理?(面试常考题)

查看对象B的prototype指向的对象是否在对象A的[[prototype]]链上

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