1.构造函数(函数对象)
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() { alert(this.name) }
}
var person1 = new Person('Zaxlct', 28, 'Software Engineer');
var person2 = new Person('Mick', 23, 'Doctor');
上面的例子中 person1 和 person2 都是 Person 的实例。这两个实例都有一个 constructor (构造函数)属性,该属性(是一个指针)指向 Person.
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
person1 和 person2 都是 构造函数 Person 的实例
一个公式:
实例的构造函数属性(constructor)指向构造函数。
2.原型对象
在 JavaScript 中,每当定义一个对象(函数也是对象)时候,对象中都会包含一些预定义的属性。其中每个函数对象都有一个prototype 属性,这个属性指向函数的原型对象。
function Person() {}
Person.prototype.name = 'Zaxlct';
Person.prototype.age = 28;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function() {
alert(this.name);
}
var person1 = new Person();
person1.sayName(); // 'Zaxlct'
var person2 = new Person();
person2.sayName(); // 'Zaxlct'
console.log(person1.sayName == person2.sayName); //true
不是每个对象都有prototype属性。只有函数对象有(每个对象都有 proto 属性,但只有函数对象才有 prototype 属性)
原型对象
原型对象,顾名思义,它就是一个普通对象(废话 = =!)。从现在开始你要牢牢记住原型对象就是 Person.prototype ,如果你还是害怕它,那就把它想想成一个字母 :
A: var A = Person.prototype
上面得改成:
Person.prototype = {
name: 'Zaxlct',
age: 28,
job: 'Software Engineer',
sayName: function() {
alert(this.name);
}
}
在上面我们给 A 添加了 四个属性:name、age、job、sayName。其实它还有一个默认的属性:constructor
在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)
上面这句话有点拗口,我们「翻译」一下:A 有一个默认的 constructor 属性,这个属性是一个指针,指向 Person。即:
Person.prototype.constructor == Person
结论:原型对象(Person.prototype)是 构造函数(Person)的一个实例。
原型对象其实就是普通对象(但 Function.prototype 除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性))
4.proto
JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做proto 的内置属性,用于指向创建它的构造函数的原型对象。
对象 person1 有一个 proto属性,创建它的构造函数是 Person,构造函数的原型对象是 Person.prototype ,所以:
person1.proto == Person.prototype
不过,要明确的真正重要的一点就是,这个连接存在于实例(person1)与构造函数(Person)的原型对象(Person.prototype)之间,而不是存在于实例(person1)与构造函数(Person)之间.
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
所有函数对象的proto都指向Function.prototype,它是一个空函数(Empty function)所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
特殊得是:
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.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind
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
再继续看:
console.log(Function.prototype.proto === Object.prototype) // true
Object.prototype.proto === null // true
在 ECMAScript 核心所定义的全部属性中,最耐人寻味的就要数 prototype 属性了。对于 ECMAScript 中的引用类型而言,prototype 是保存着它们所有实例方法的真正所在。换句话所说,诸如 toString()和 valuseOf() 等方法实际上都保存在 prototype 名下,只不过是通过各自对象的实例访问罢了
思考:
person1.proto 是什么?
Person.proto 是什么?
Person.prototype.proto 是什么?
Object.proto 是什么?
Object.prototype__proto__ 是什么?
二:
var Person = new Object()
Person 是 Object 的实例,所以 Person 继承了Object 的原型对象Object.prototype上所有的方法
复习一下:
所有函数对象的 __proto__ 都指向 Function.prototype,它是一个空函数(Empty function)
以及最开始得出得结论:
所有对象的 __proto__ 都指向其构造器的 prototype
每个对象都有一个 constructor 属性,可以获取它的构造器,因此以下打印结果也是恒等的
function Person(name) {
this.name = name;
}
var p = new Person('jack')
console.log(p.__proto__ === Person.prototype) // true
比较
function Person(name) {
this.name = name
}
var p = new Person('jack')
console.log(p.__proto__ === p.constructor.prototype) // true
可以看到p.proto与Person.prototype,p.constructor.prototype都是恒等的,即都指向同一个对象。
继续看:
第一种情况:
function Person(name) {
this.name = name
}
// 重写原型直接给原型赋值一个对象
Person.prototype = {
getName: function() {}
}
var p = new Person('jack')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // false
第二种情况
var p = {}
console.log(Object.prototype) // 为一个空的对象{}
console.log(p.constructor === Object) // 对象直接量方式定义的对象其constructor为Object
console.log(p.constructor.prototype === Object.prototype) // 为true,不解释(๑ˇ3ˇ๑)
五,原型链
复习一遍
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
疑惑点:
1.Object.proto === Function.prototype // true
Object 是函数对象,是通过new Function()创建的,所以Object.proto指向Function.prototype。(参照第八小节:「所有函数对象的proto都指向Function.prototype」)
2.Function.proto === Function.prototype // true
Function 也是对象函数,也是通过new Function()创建,所以Function.proto指向Function.prototype。
3.Function.prototype.proto === Object.prototype //true
其实这一点我也有点困惑,不过也可以试着解释一下。
Function.prototype是个函数对象,理论上他的proto应该指向 Function.prototype,就是他自己,自己指向自己,没有意义。
JS一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype.proto === null,保证原型链能够正常结束。
原型和原型链是JS实现继承的一种模型。
原型链的形成是真正是靠proto 而非prototype