前言
首先廣為所知的
“萬(wàn)物皆對(duì)象”是錯(cuò)誤
的。
簡(jiǎn)單基本類型(string愕秫,number,boolean焰络,null戴甩,undefined
)不是對(duì)象。
復(fù)雜基本類型(object
)才是對(duì)象舔琅;但是object有九個(gè)內(nèi)置對(duì)象(String 等恐,Number, Boolean,Object课蔬,F(xiàn)unction囱稽, Array,Date二跋, RegExp战惊,Error
)
舉個(gè)例子:
var num1 = 123;
typeof num1; // "Number"
num1 instanceof Number; // false
var num2 = new Number(123);
typeof num2; // "object"
num2 instanceof Number; // true
其實(shí)num1這種字面量形式,獲取長(zhǎng)度扎即,訪問(wèn)值其實(shí)是不生效的吞获。但是js引擎自動(dòng)幫我們轉(zhuǎn)成Number這種形式了。如num1.length
谚鄙。
我們這里簡(jiǎn)單介紹了各拷,不做深入探討,畢竟js引擎幫我們做了闷营,記住一句話烤黍,Object是所有對(duì)象的基類
。
接下來(lái)用最通俗易懂的方式給大家解釋各種學(xué)術(shù)名稱的原理:
一傻盟、__proto__
(指針)
Firefox和Chrome 提供__proto__
訪問(wèn)器速蕊,ECMA標(biāo)準(zhǔn)是[[Prototype]]
,它是對(duì)象內(nèi)置屬性無(wú)法訪問(wèn)娘赴,可以通過(guò)Object.getPrototypeOf()標(biāo)準(zhǔn)方法訪問(wèn)該屬性规哲。
從最簡(jiǎn)單代碼開(kāi)始:
var obj = {};
console.log(obj);
打印的樣子:
只要是對(duì)象都有
__proto__
屬性,最底層的constructor
是Object
诽表,也印證了我那句Object是所有對(duì)象的基類
唉锌。
二、prototype
(原型)
定義
其中每個(gè)函數(shù)對(duì)象都有一個(gè)prototype 屬性竿奏,這個(gè)屬性指向函數(shù)的原型對(duì)象糊秆。
與__proto__
區(qū)別:
1:每個(gè)對(duì)象都有
__proto__
屬性,但只有函數(shù)對(duì)象才有prototype
屬性议双。
2:__proto__
指向的是當(dāng)前對(duì)象的原型對(duì)象,而prototype
指向的捉片,是以當(dāng)前函數(shù)作為構(gòu)造函數(shù)構(gòu)造出來(lái)的對(duì)象的原型對(duì)象平痰。
function Foo() {
var name = '小米';
}
Foo.prototype.sayHello = function() {
console.log('hello 靚仔');
};
console.log(Foo.prototype);
大家可以看到
Foo.prototype
有了sayHello
的函數(shù),自然可以調(diào)用伍纫。這里有兩個(gè)問(wèn)題宗雇?
-
sayHello
方法想獲取Foo
函數(shù)中的name
怎么辦? - 圖中
constructor的prototype
里面也有sayHello
函數(shù)是怎么回事莹规?
2.1 解答問(wèn)題1
這就是我們?yōu)楹问褂?code>new進(jìn)行構(gòu)造函數(shù)的原因赔蒲,因?yàn)樗泄灿脤傩裕瘮?shù)共使用,還能繼承舞虱。
function Foo() {
this.name = '小明';
}
Foo.prototype.sayHello = function() {
console.log('hello' + this.name);
};
// var obj = {};
// obj.__proto__ = Foo.prototype;
// Foo.call(obj);
// var f = obj;
var f = new Foo();
console.log(f.sayHello());
這里解釋兩件事情:(大廠面試必問(wèn))
-
new是什么
欢际,就是我注釋掉的代碼。 -
為何用prototype創(chuàng)建函數(shù)sayHello
矾兜,為了避免每一次new Foo()就創(chuàng)建一次sayHello损趋,占用內(nèi)存,消耗性能椅寺。
2.2 解答問(wèn)題2
直接引出constructor浑槽。
三、constructor
(構(gòu)造函數(shù))
function Foo() {
// ...
}
console.log(Foo.prototype.constructor === Foo); // true
從中可以看出constructor
是函數(shù)Foo的prototype內(nèi)置屬性
返帕,指向函數(shù)本身桐玻。就是這么簡(jiǎn)單。
繼續(xù)看代碼:
function Foo() {
// ...
}
var a = new Foo();
console.log(a.constructor === Foo); // true
是不是說(shuō)明構(gòu)造函數(shù)a的constructor指向Foo荆萤,答案是否定的镊靴。
繼續(xù)改代碼
function Foo() {
// ...
}
Foo.prototype.constructor = {}
var a = new Foo();
console.log(a.constructor === Foo); // false
原因很簡(jiǎn)單,就是Foo.prototype的constructor被我們?cè)O(shè)置為{}了观腊,也就是說(shuō)a.constructor是{}了邑闲,說(shuō)明這個(gè)constructor不安全,在某些情況梧油,我們得讓它恢復(fù)苫耸,所以你會(huì)看到如下代碼:
function Person() {}
Person.prototype = {
constructor: Person, //這里指向Person,就不會(huì)丟失了
name: '欣雨',
age: 19,
sayName: function() {
console.log(this.name + '年齡' + this.age);
},
};
// console.log(Person.prototype);
var p = new Person();
p.sayName(); // 欣雨年齡19
constructor
介紹完了儡陨,我們來(lái)解釋一下2.2的問(wèn)題吧褪子,上述注釋代碼的console.log(Person.prototype)
打開(kāi),打印一下看看:
只要你通過(guò)原型prototype
創(chuàng)建屬性和方法時(shí)骗村,那么Person.prototype
的constructor
下就會(huì)有prototype
屬性包含你創(chuàng)建的嫌褪。(這里不是很重要,知道就好)
就是我在介紹2prototype
(原型)所說(shuō):__proto__
指向的是當(dāng)前對(duì)象的原型對(duì)象胚股,而prototype
指向的笼痛,是以當(dāng)前函數(shù)作為構(gòu)造函數(shù)構(gòu)造出來(lái)的對(duì)象的原型對(duì)象。
四琅拌、原型鏈
定義:
原型鏈就是通過(guò)proto屬性從當(dāng)前對(duì)象開(kāi)始查找它的原型對(duì)象(通過(guò)prototype生成的)缨伊,一直查找到null為止。
function Person() {}
Person.prototype = {
constructor: Person, //這里指向Person进宝,就不會(huì)丟失了
name: '欣雨',
age: 19,
sayName: function() {
console.log(this.name + '年齡' + this.age);
},
};
var p = new Person();
console.log(p);
打印的p下面就是空對(duì)象刻坊,而需要的屬性在proto下面。
類型:
默認(rèn)的原型鏈結(jié)構(gòu)就是:當(dāng)前對(duì)象 -> 構(gòu)造函數(shù).prototype -> Object.prototype -> null
繼承改變默認(rèn)原型鏈結(jié)構(gòu)党晋,其實(shí)通過(guò)_proto查找即可谭胚。
五徐块、函數(shù)的構(gòu)造函數(shù)Function
普通函數(shù):
function foo(num) {
console.log(num);
}
foo(2); // 2
構(gòu)造函數(shù):
var foo = new Function('num', 'console.log( num )');
foo(2); // 2
好處就是:
Function是使用字符串構(gòu)建函數(shù),那么就可以在程序運(yùn)行過(guò)程中構(gòu)建函數(shù)灾而。
以前的函數(shù)必須一開(kāi)始就寫好胡控,再經(jīng)過(guò)預(yù)解析,一步一步的運(yùn)行绰疤。
寫一些底層代碼铜犬,為了性能可以使用。
六 instanceof 原理
A instanceof B
的原理?(面試城崆欤考題)
查看對(duì)象B的prototype指向的對(duì)象是否在對(duì)象A的[[prototype]]鏈上
即
A.__proto__ === B.prototype