首先,JavaScript中万物皆对象。
然后,其中对象分为两种:普通对象和函数对象。Object ,Function 是JS自带的函数对象。
普通对象和函数对象:
// 普通对象的定义方法
let a = new Object(); // typeof a === object
let b = {}: // typeof b === object
let c = new Person(); // typeof c === object
// 函数对象
let a2 = function() {}; // typeof a2 === function
let b2 = new Function('str', 'console.log(str)'); // typeof b2 === function
function c2() {} // typeof c2 === function
typeof Object === function
typeof Function === function
总结:
凡是通过new Function() 创建的对象就是函数对象,其他都是普通对象。Object, Function 也是由new Function创建的。
函数对象有prototype属性,该属性指向一个对象,就是我们所说的原型对象。
普通对象有__proto__属性,该属性指向创建它的函数对象的原型对象(prototype)。
prototype对象里面包含constructor构造器,该构造器是对函数对象的引用。这是一种循环引用。
也就是说:
// 举个例子
var Person = function(name){
this.name = name
};
Person.prototype.getName = function(){
return this.name;
};
var zjh = new Person('zhangjiahao’);
zjh.getName(); //zhangjiahao
Person.prototype.constructor === Person; //true
原型对象(prototype)是一个普通对象,它也会有__proto__属性的,(Function.prototype除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性)),那么这个属性具体干嘛呢?
__proto__就是我们经常说的原型链的继承的关键所在。
有两点需要注意:
(1)注意Object.constructor===Function;//true 本身Object就是Function函数构造出来的
(2)如何查找一个对象的constructor,就是在该对象的原型链上寻找碰到的第一个constructor属性所指向的对象
原型链
JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。
zjh.__proto__ === Person.prototype; // true
同样,Person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype;
Person.prototype.__proto__ === Object.prototype; // true
继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null;
Object.prototype.__proto__ === null; // true
Object是函数对象,是通过new Function()创建,所以Object.__proto__指向Function.prototype。
Object.__proto__ === Function.prototype // true
Function 也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。
Function.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype //true
Function.prototype是个函数对象,理论上他的proto应该指向 Function.prototype,就是他自己,自己指向自己,没有意义。
JS一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype.proto === null,保证原型链能够正常结束。
var animal = function(){};
var dog = function(){};
animal.price = 2000;
dog.prototype = animal;
var tidy = new dog();
console.log(dog.price) //undefined
console.log(tidy.price) // 2000
这说明什么问题呢,执行dog.price的时候,发现没有price这个属性,虽然prototype指向的animal有这个属性,但它并没有去沿着这个“链”去寻找。同样,执行tidy.price的时候,也没有这个属性,但是__proto__指向了animal,它会沿着这个链去寻找,animal中有price属性,所以tidy.price输出2000。
由此得出,原型链的真正形成是靠的__proro__,而不是prototype。
因此,如果在这样指定dog.proto = animal。那dog.price = 2000。