七. 函数对象
所有的构造器都来自于 Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind。
所有构造器(含内置及自定义)的__proto__都是Function.prototype,那Function.prototype的__proto__是谁呢?如下console.log(Function.prototype.proto === Object.prototype) // true这说明所有的构造器也都是一个普通 JS 对象,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。
最后Object.prototype的proto是谁?Object.prototype.proto === null // true已经到顶了,为null
八. Prototype
toString()和 valuseOf() 等方法实际上都保存在 prototype 名下
var Person = new Object()Person 是 Object 的实例,所以 Person 继承了Object 的原型对象Object.prototype上所有的方法:
Object.getOwnPropertyNames获取所有(包括不可枚举的属性)的属性名不包括 prototy 中的属性,返回一个数组:
var arrayAllKeys = Array.prototype; // [] 空数组
// 只得到 arrayAllKeys 这个对象里所有的属性名(不会去找 arrayAllKeys.prototype 中的属性)
console.log(Object.getOwnPropertyNames(arrayAllKeys));
/* 输出:
["length", "constructor", "toString", "toLocaleString", "join", "pop", "push",
"concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach",
"some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight",
"entries", "keys", "copyWithin", "find", "findIndex", "fill"]
*/
var num = [1];
console.log(num.hasOwnPrototype()) // false (输出布尔值而不是报错)可以通过这个判断,这个属性是实例的,还是原型的。
Array.prototype 继承了对象的所有方法,当你用num.hasOwnPrototype()时,JS 会先查一下它的构造函数 (Array) 的原型对象 Array.prototype 有没有有hasOwnPrototype()方法,没查到的话继续查一下 Array.prototype 的原型对象 Array.prototype.__proto__有没有这个方法。
所有函数对象****proto都指向 Function.prototype,它是一个空函数(Empty function)
所有对象的 __proto__ 都指向其构造器的 prototype
JS 内置构造器:
var obj = {name: 'jack'}
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)
九. 原型链
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
Object.proto === Function.prototype // trueObject 是函数对象,是通过new Function()创建的,所以Object.__proto__指向Function.prototype。(参照第八小节:「所有函数对象的__proto__都指向Function.prototype」)
Function.proto === Function.prototype // trueFunction 也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。
Function.prototype.__proto__ === Object.prototype //true
总结:
原型和原型链是JS实现继承的一种模型。
原型链的形成是真正是靠__proto__ 而非prototype
实例(person1)和 原型对象(Person.prototype)存在一个连接。不过,要明确的真正重要的一点就是,这个连接存在于实例(person1)与构造函数的原型对象(Person.prototype)之间,而不是存在于实例(person1)与构造函数(Person)之间。