原型和原型链

我们将对象分为函数对象普通对象,函数对象的级别要要高于普通对象,可以通过函数对象创建普通对象,但是无法通过普通对象创建函数对象。

何为js原型


每一个js对象(null除外)都和另一个对象相关联,另一个对象就是原型,每一个对象都从原型继承属性
所有通过对象直接量创建的对象都具有同一个原型对象,可以通过Object.prototype获取对原型对象的引用。

//dmeo1
var obj =new Object()
//等价于 const obj ={}
//等价于const obj = Object.create()
alert(obj.prototype)//undefined
alert(Object.prototype)//[object Object]
//demo2
function fun(){
    console.log("这是一个自定义构造函数")
};
alert(fun.prototype)//[object Object]

看以上代码,obj 为普通对象,obj的prototype为undefined,Object为js内置构造函数,Object存在prototype
我们得出以下结论
每一个函数对象都有一个prototype属性,但是普通对象是没有的;
换个方式再说一遍,只有函数对象才会存在prototype属性,普通的对象不存在

function fun(){
    console.log("这是一个自定义构造函数")
};
console.log(fun.prototype)
var obj = {}
console.log(obj.__proto__);

构造函数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.prototypes是Foo 的实例。
也就是在 Foo 创建的时候,创建了一个它的实例对象并赋值给它的 prototype

原型对象prototype


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

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

隐式原型_proto_


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

// 普通对象的\__proto\__指向当前函数对象的原型,
console.log('a'.__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('a'.__proto__===String.prototype);//true
console.log(String.prototype.__proto__===Object.prototype);//true
//等量代换,得出以下结论
console.log('陌上寒'.__proto__.__proto__===Object.prototype);//true

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

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

这就是原型链

  • 原型对象是构造函数的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
原型链
原型链是实现继承的主要方法。

你可能感兴趣的:(原型和原型链)