关于javascript的原型和原型链,看我就够了

温故

我们先回顾一下前两天讨论的内容

创建对象的三种方式

  • 通过对象直接量
  • 通过new创建对象
  • 通过Object.create()

js中对象分为两种

  • 函数对象
  • 普通对象

原型对象prototype

  • 每一个函数对象都有一个prototype属性,但是普通对象是没有的;
  • 普通对象都是通过函数创建的

在 ECMAScript 核心所定义的全部属性中,最耐人寻味的就要数 prototype 属性了。对于 ECMAScript 中的引用类型而言,prototype 是保存着它们所有实例方法的真正所在。换句话所说,诸如 toString()和 valuseOf() 等方法实际上都保存在 prototype 名下,只不过是通过各自对象的实例访问罢了。----《JavaScript 高级程序设计》

构造函数constructor

function Foo(name) {
    this.name = name;
}
var foo = new Foo('陌上寒');
 console.log(Foo.prototype.constructor===Foo)//true
 console.log(foo.constructor===Foo);//true
复制代码

原型对象有一个constructor属性,指向该原型对象对应的构造函数 foo 为什么有 constructor 属性?那是因为 foo 是 Foo 的实例。 那 Foo.prototype 为什么有 constructor 属性??同理, Foo.prototype Foo 的实例。 也就是在 Foo 创建的时候,创建了一个它的实例对象并赋值给它的 prototype

隐式原型_proto_

在Firefox、Safari 和 Chrome 的每个对象上都有这个_proto_,属性 ,而在其他浏览器中是完全不可见的为了确保浏览器兼容性问题,不要直接使用 proto 属性)

// 普通对象的\__proto\__指向当前函数对象的原型,
console.log('陌上寒'.__proto__===String.prototype);//true
//原型对象(也属于普通对象)的__proto__指向当前函数对象的原型
console.log(String.prototype.__proto__===Object.prototype);//true
//内置函数对象的\__proto\__指向的都是ƒ () { [native code] }
console.log(Object.__proto__);//ƒ () { [native code] }
//Object的原型对象的\__proto\__为null
console.log(Object.prototype.__proto__)//null
复制代码
  • 普通对象的__proto__指向当前函数对象的原型,
  • 原型对象(也属于普通对象)的__proto__指向当前函数对象的原型
  • 内置函数对象的__proto__指向的都是ƒ () { [native code] }
  • 所有对象(除了Object.prototype)都存在_proto_
  • Object的原型对象的__proto__为null 好好消化上面的知识点,有助于我么讨论新的内容==>原型链

知新

原型链

  • 原型对象prototype
  • 构造函数constructor
  • 隐式原型_proto_ 通过三者之间的联系,形成了原型链 继续看一下我门昨天讨论过的代码
console.log('陌上寒'.__proto__===String.prototype);//true
console.log(String.prototype.__proto__===Object.prototype);//true
//等量代换,得出以下结论
console.log('陌上寒'.__proto__.__proto__===Object.prototype);//true
复制代码

我们刚才说过,普通对象的__proto__指向当前函数对象的原型 我们刚才还说过,普通对象都是通过函数创建的 根据以上两个结论我们分析一下上面的代码 ‘陌上寒’是字符串类型,’陌上寒’的构造函数是String(), 所以’陌上寒’的__proto__指向String的原型 String是js的内置构造函数,内置构造函数继承自Object String的原型对象String.prototype也是一个普通对象,它的__proto__指向Object的原型,即Object.prototype 所以

console.log('陌上寒'.__proto__.__proto__===Object.prototype);//true
复制代码

这就是原型链 我们继续品读以下代码

//我们创建一个构造函数Foo(要记得,构造函数命名,首字母要大写)
function Foo() {}
//通过我们自定义的构造函数。通过new操作符,我们实例化出来一个对象foo
const foo = new Foo()
//对象的__proto__指向当前函数对象(foo是同构Foo实例化出来的,所以foo的函数对象是Foo)的原型
console.log(foo.__proto__===Foo.prototype);
//原型对象也存在__proto__,指向该原型对象(Foo.prototype)所对应的函数对象(Object)的原型(好像有点绕,看代码就没那么绕了)
console.log(Foo.prototype.__proto__===Object.prototype);//true
//上面的如果懂了,这行代码就简单了,一个数学的等量代换,就得出了结论
console.log(foo.__proto__.__proto__===Object.prototype);//true
console.log('---我是分割线----');
//我们通过字面量创建了一个对象,等同于 const obj = new Object()
const obj = {}
//obj 是通过内置构造函数Object创建的,所以,obj的__proto__指向它的函数对象(Object)的原型(prototype)即:Object.prototype
console.log(obj.__proto__===Object.prototype);//true
console.log('---我是分割线----');//true
//创建一个对象b
const b = {}
//我们之前说过创建对象有三种方式,我们使用第三种方式创建一个对象b1,对象b1继承自对象b,也就是说,对象b是对象b1的__proto__
const b1 = Object.create(b)
//对象b是对象b1的__proto__
console.log(b1.__proto__===b);//true
//前面已经证实过,b.__proto__==Object.prototype,不再赘述
console.log(b.__proto__==Object.prototype);//true
//等量代换就得出以下结论
console.log(b1.__proto__.__proto__===b.__proto__);//true
console.log(b1.__proto__.__proto__==Object.prototype);//true
复制代码

我偷了一张图?,我们看一下

 

啊,好像很简单,我们看一下

 

//自定义构造函数A(构造函数命名首字母大写)创建方式等同于var A  = new Function()
var A = function(){}//等同于var A  = new Function()
//通过构造函数A,使用new操作符实例化一个对象a(A是a的构造函数,a是A创建出来的)
var a = new A()
//对象的的__proto__指向它所对象函数对象(A)的原型(A.prototype)
console.log(a.__proto__===A.prototype)//true
//A是通过js内置构造函数Function创建出来的,然而
console.log(A.prototype.__proto__===Function.prototype);//false
console.log(A.prototype.__proto__==Object.prototype);//true
console.log(Function.prototype)//ƒ () { [native code] }
复制代码

Function特例

我们重新修改一下上面的代码

var A  = new Function()
var a = new A()
复制代码

A.prototype是个函数对象,理论上他的__proto__应该指向 Function.prototype,就是他自己,自己指向自己,没有意义。 js一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype._proto_ === null,保证原型链能够正常结束。 事实验证了这样一个道理

console.log(a.__proto__===A.prototype)//true
console.log(A.prototype.__proto__===Function.prototype);//false
console.log(A.prototype.__proto__==Object.prototype);//true
console.log(a.__proto__.__proto__==Object.prototype);//true
复制代码

A的原型对象的__proto__指向的是Object的原型 再看一张图

 

图片来源

 

  • 原型对象是构造函数的prototype属性,是所有实例化对象共享属性和方法的原型对象。
  • 实例化对象通过new构造函数得到,都继承了原型对象的属性和方法。
  • 原型对象中有个隐式的constructor,指向了构造函数本身。

再看一张图,细细品味

 

图片地址

 

总结

今天先讨论到这里,我们一起对今天的内容做一个总结 所有函数对象的\ _proto_ 都指向 Function.prototype,它是一个空函数(Empty function)ƒ () { [native code] }

var obj = {name: '陌上寒'}
var arr = [1,2,3]
var reg = /hello/g
var date = new Date
var err = new Error('exception')
console.log(obj.__proto__ === Object.prototype) // true
console.log(arr.__proto__ === Array.prototype)  // true
console.log(reg.__proto__ === RegExp.prototype) // true
console.log(date.__proto__ === Date.prototype)  // true
console.log(err.__proto__ === Error.prototype)  // true
复制代码

所有对象的 _proto_ 都指向其构造器的 prototype 原型链 原型链是实现继承的主要方法。

自己是由自己创建的,好像不符合逻辑,但仔细想想,现实世界也有些类似,你是怎么来的,你妈生的,你妈怎么来的,你姥姥生的,……类人猿进化来的,那类人猿从哪来,一直追溯下去……,就是无,(NULL生万物) 正如《道德经》里所说“无,名天地之始”。

function Person(){}
var person1 = new Person();
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype) //true
console.log(Object.prototype.__proto__) //null

Person.__proto__ === Function.prototype; //true
console.log(Function.prototype)// function(){} (空函数)

var num = new Array()
console.log(num.__proto__ === Array.prototype) // true
console.log( Array.prototype.__proto__ === Object.prototype) // true
console.log(Array.prototype) // [] (空数组)
console.log(Object.prototype.__proto__) //null
console.log(Array.__proto__ === Function.prototype)// true
复制代码

我们一起连续讨论了那么多,相信你一定对js原型和原型链有了些认识,但是光有认识还是不够的,原型和原型链在实际场景中是怎么发挥作用的呢?我们如何将原型链的相关技能投入到开发中呢?我们明天继续讨论javascript的原型和原型链,不见不散

原文链接

相关文章

关于javascript的原型和原型链,看我就够了(一)

关于javascript的原型和原型链,看我就够了(二)

关于javascript的Object. hasOwnProperty,看我就够了

参考链接

JavaScript之原型与原型链

图解prototype、proto和constructor的三角关系

Function.proto===Function.prototype怎么解释?

最详尽的 JS 原型与原型链终极详解,没有「可能是」。(一)


作者:陌上寒
链接:https://juejin.im/post/5bdefa3c6fb9a049e129a575
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值