js中原型和原型链全解析

一. 普通对象与函数对象
JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object 、Function 是 JS 自带的函数对象。

var o1 = {
    
    }; 
var o2 =new Object();
var o3 = new f1();

function f1(){
    
    }; 
var f2 = function(){
    
    };
var f3 = new Function('str','console.log(str)');

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

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

console.log(typeof o1); //object 
console.log(typeof o2); //object 
console.log(typeof o3); //object

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的。

二. 构造函数

实例的构造函数属性(constructor)指向构造函数。

console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true 

三. 原型对象
其中每个函数对象都有一个prototype 属性,这个属性指向函数的原型对象。
每个对象都有 proto 属性,但只有函数对象才有 prototype 属性
原型对象就是一个普通对象
在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)

Person.prototype.constructor == Person  

实例的构造函数属性(constructor)指向构造函数 (实例继承了函数对象中的原型对象里的constructor,所以实例对象有constructor属性)
person1.constructor == Person

原型对象(Person.prototype)是构造函数(Person)的一个实例。
原型对象其实就是普通对象(但 Function.prototype 除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性)),因此所有的原型对象都没有prototype属性 。

function Person(){
    
    };
 console.log(Person.prototype) //Person{}
 console.log(typeof Person.prototype) //Object
 console.log(typeof Function.prototype) // Function,这个特殊
 console.log(typeof Object.prototype) // Object
 console.log(typeof Function.prototype.prototype) //undefined

那么Function.prototype 为什么是函数对象呢?
var A = new Function ();
Function.prototype = A;

上文提到凡是通过 new Function( ) 产生的对象都是函数对象。因为 A 是函数对象,所以Function.prototype 是函数对象。其它的原型对象都不是通Function来构造的

那原型对象是用来做什么的呢?主要作用是用于继承。通过给 Person.prototype 设置了一个函数对象的属性,那有 Person 的实例(person1)出来的普通对象就继承了这个属性。

四. __ proto__
JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__ 的内置属性,用于指向创建它的构造函数的原型对象。
对象 person1 有一个 __proto__属性,创建它的构造函数是 Person,构造函数的原型对象是 Person.prototype ,所以:

person1.__proto__ == Person.prototype
Person.prototype.constructor == Person;
person1.__proto__ == Person.prototype;
person1.constructor == Person;

要明确的真正重要的一点就是,这个连接存在于实例(person1)与构造函数(Person)的原型对象(Person.prototype)之间,而不是存在于实例(person1)与构造函数(Person)之间。

五. 构造器

创建对象的构造器不仅仅有 Object,也可以是 Array,Date,Function等。
这些构造器都是函数对象:
typeof (Object,Function,Array,Date,Number,String,Bolean) 结果均是function

六. 原型链

person1.__proto__ ===Person.prototype
Person.__proto__ ===Function.prototype
Person.prototype.__proto__===Object.prototype
Object.__proto__===Function.prototype
Object.prototype__proto__===null 

七. 函数对象
// 所有函数对象的proto都指向Function.prototype,它是一个空函数(Empty function)

Number.__proto__ === Function.prototype  // true
Number.constructor == Function //true

Boolean.__proto__ === Function.prototype // true
Boolean.constructor == Function //true

String.__proto__ === Function.prototype  // true
String.constructor == Function //true

所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身

Object.__proto__ === Function.prototype  // true
Object.constructor == Function // true

所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身

Function.__proto__ === Function.prototype // true
Function.constructor == Function //true

Array.__proto__ === Function.prototype   // true
Array.constructor == Function //true

RegExp.__proto__ === Function.prototype  // true
RegExp.constructor == Function //true

Error.__proto__ === Function.prototype   // true
Error.constructor == Function //true

Date.__proto__ === Function.prototype    // true
Date.constructor == Function //true

JavaScript中有内置(build-in)构造器/对象共计12个(ES5中新加了JSON),这里列举了可访问的8个构造器。剩下如Global不能直接访问,Arguments仅在函数调用时由JS引擎创建,Math,JSON是以对象形式存在的,无需new。它们的proto是Object.prototype。如下

Math.__proto__ === Object.prototype  // true
Math.construrctor == Object // true

JSON.__proto__ === Object.prototype  // true
JSON.construrctor == Object //true

上面说的函数对象当然包括自定义的。如下

function Person() {
    
    }
var Perosn = function() {
    
    }
console.log(Person.__proto__ === Function.prototype) // true
console.log(Man.__proto__ === Function.prototype)    // true

所有的构造器都来自于 Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind

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

Function.prototype也是唯一一个typeof Function.prototype为 function的prototype。其它的构造器的prototype都是一个对象

console.log(typeof Function.prototype) // function
console.log(typeof Object.prototype)   // object
console.log(typeof Number.prototype)   // object
console.log(typeof Boolean.prototype)  // object
console.log(typeof String.prototype)   // object
console.log(typeof Array.prototype)    // object
console.log(typeof RegExp.prototype)   // object
console.log(typeof Error.prototype)    // object
console.log(typeof Date.prototype)     // object
console.log(typeof Object.prototype)   // object

知道了所有构造器(含内置及自定义)的__proto__都是Function.prototype,那Function.prototype的__proto__是谁呢?
相信都听说过JavaScript中函数也是一等公民,那从哪能体现呢?如下
console.log(Function.prototype.proto === Object.prototype) // true

最后Object.prototype的proto是谁?

Object.prototype.__proto__ === null // true

八. Prototype
对于 ECMAScript 中的引用类型而言,prototype 是保存着它们所有实例方法的真正所在。换句话所说,诸如 toString()和 valuseOf() 等方法实际上都保存在 prototype 名下,只不过是通过各自对象的实例访问罢了。

当我们创建一个函数时:
var Person = new Object()
Person 是 Object 的实例,所以 Person 继承了Object 的原型对象Object.prototype上所有的方法:没查到的话继续查一下 Person.prototype 的原型对象 Person.prototype.__proto__有没有这个方法。
Object 的每个实例都具有以上的属性和方法。
所以我可以用 Person.constructor 也可以用 Person.hasOwnProperty。

猜你喜欢

转载自blog.csdn.net/lyj223061/article/details/100127586