一.普通對(duì)象與函數(shù)對(duì)象
js中萬(wàn)物皆對(duì)象!但對(duì)象也是有區(qū)別的。分為普通對(duì)象和函數(shù)對(duì)象,Object 、Function 是 JS 自帶的函數(shù)對(duì)象。下面舉例說明
var o1 = {};
var o2 = new Object();
var o3 = new f1();
function f1(){};
var f2 = function(){};
var f3 = new Function('fn','console.log(fn)');
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 為普通對(duì)象,f1 f2 f3 為函數(shù)對(duì)象。
怎么區(qū)分,其實(shí)很簡(jiǎn)單,凡是通過 new Function() 創(chuàng)建的對(duì)象都是函數(shù)對(duì)象,其他的都是普通對(duì)象。
Function Object 最后是通過 New Function()創(chuàng)建的。
二.構(gòu)造函數(shù)
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() { alert(this.name) }
}
var person1 = new Person('張三', 18, '搬磚');
var person2 = new Person('李四', 18, '和泥');
上面的例子中 person1 和 person2 都是 Person 的實(shí)例。
這兩個(gè)實(shí)例都有一個(gè) constructor (構(gòu)造函數(shù))屬性,該屬性(是一個(gè)指針)指向 Person。
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
記住兩個(gè)概念(構(gòu)造函數(shù)、實(shí)例):
person1 和 person2 都是 構(gòu)造函數(shù) Person 的實(shí)例
公式:
實(shí)例的構(gòu)造函數(shù)屬性(constructor)指向構(gòu)造函數(shù)
三. 原型對(duì)象
在 JavaScript 中,每當(dāng)定義一個(gè)對(duì)象(函數(shù)也是對(duì)象)時(shí)候,對(duì)象中都會(huì)包含一些預(yù)定義的屬性。其中每個(gè)函數(shù)對(duì)象都有一個(gè)prototype 屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。
function Person() {}
Person.prototype.name = '張三';
Person.prototype.age = 18;
Person.prototype.job = '搬磚';
Person.prototype.sayName = function() {
alert(this.name);
}
var person1 = new Person();
person1.sayName(); // '張三'
var person2 = new Person();
person2.sayName(); // '張三'
console.log(person1.sayName == person2.sayName); //true

上圖中可以知道,實(shí)例
__protpo__指向的是原型對(duì)象。實(shí)例的構(gòu)造函數(shù)的prototype也是指向的原型對(duì)象。
原型對(duì)象的construor指向的是構(gòu)造函數(shù)。
牢記!以下四條:
1.每個(gè)對(duì)象都具有一個(gè)名為
__proto__的屬性;
2.每個(gè)構(gòu)造函數(shù)都具有一個(gè)名為prototype的方法;
3.每個(gè)對(duì)象的__proto__屬性指向自身構(gòu)造函數(shù)的prototype;
4.每個(gè)對(duì)象都有__proto__屬性,但只有函數(shù)對(duì)象才有 prototype 屬性
四、原型鏈
簡(jiǎn)單理解就是原型組成的鏈,對(duì)象的__proto__它的是原型,而原型也是一個(gè)對(duì)象,也有__proto__屬性,原型的__proto__又是原型的原型,就這樣可以一直通過__proto__想上找,這就是原型鏈,當(dāng)向上找找到Object的原型的時(shí)候,這條原型鏈就算到頭了。
原型對(duì)象和實(shí)例之間有什么作用
通過一個(gè)構(gòu)造函數(shù)創(chuàng)建出來的多個(gè)實(shí)例,如果都要添加一個(gè)方法,給每個(gè)實(shí)例去添加并不是一個(gè)明智的選擇。這時(shí)就該用上原型了。
在實(shí)例的原型上添加一個(gè)方法,這個(gè)原型的所有實(shí)例便都有了這個(gè)方法。
var Met = function (name) { this.name = name; }
var met = new Met('met')
var met1 = new Met()
met.__proto__.say=furnction(){
console.log('hello world')
}
met.say()
met1.say()
按照J(rèn)S引擎的分析方式,在訪問一個(gè)實(shí)例的屬性的時(shí)候,現(xiàn)在實(shí)例本身中找,如果沒找到就去它的原型中找,還沒找到就再往上找,直到找到。這就是原型鏈。
Met.__proto__===Function.prototype //true
只有函數(shù)有prototype,對(duì)象是沒有的
但是函數(shù)也是有__proto__的,因?yàn)楹瘮?shù)也是對(duì)象。函數(shù)的__proto__指向的是Function.prototype。也就是說普通函數(shù)是Function這個(gè)構(gòu)造函數(shù)的一個(gè)實(shí)例。
instanceof原理

instanceof是判斷實(shí)例對(duì)象的
__proto__和生成該實(shí)例的構(gòu)造函數(shù)的prototype是不是引用的同一個(gè)地址。注意:實(shí)例的instanceof在比較的時(shí)候,與原型鏈上向上找的的構(gòu)造函數(shù)相比都是true
met.__proto__===Met.prototype//true
met instanceof Met //true
Met.prototype===Object.prototype//false
Met.prototype.__proto__===Object.prototype//true
met instanceof Object //true
met.__proto__.constructor===Met//true
met.__proto__.constructor===Object//fasle
new運(yùn)算符的原理
1.一個(gè)新對(duì)象被創(chuàng)建。它繼承自foo.prototype。
2.構(gòu)造函數(shù)返回一個(gè)對(duì)象。在執(zhí)行的時(shí)候,相應(yīng)的傳參會(huì)被傳入,同時(shí)上下文(this)會(huì)被指定為這個(gè)新的實(shí)例。
3.new foo等同于new foo(), 只能用在不傳遞任何參數(shù)的情況
4.如果構(gòu)造函數(shù)反悔了一個(gè)對(duì)象,那個(gè)這個(gè)對(duì)象會(huì)取代整個(gè)new出來的結(jié)果。如果構(gòu)造函數(shù)沒有返回對(duì)象,那個(gè)new出來的結(jié)果為步驟1創(chuàng)建的對(duì)象。