JavaScript相關(guān)

1璧亮、JavaScript初識(shí)

1. 說幾條 JavaScript 的基本規(guī)范?

(1)一個(gè)函數(shù)作用域中所有的變量聲明應(yīng)該盡量提到函數(shù)首部蒸健,用一個(gè) var 聲明衡创,不允許出現(xiàn)兩個(gè)連續(xù)的 var 聲明,聲明時(shí) 如果變量沒有值峡蟋,應(yīng)該給該變量賦值對(duì)應(yīng)類型的初始值坟桅,便于他人閱讀代碼時(shí),能夠一目了然的知道變量對(duì)應(yīng)的類型值蕊蝗。

(2)代碼中出現(xiàn)地址仅乓、時(shí)間等字符串時(shí)需要使用常量代替。

(3)在進(jìn)行比較的時(shí)候吧蓬戚,盡量使用'===', '!=='代替'==', '!='夸楣。

(4)不要在內(nèi)置對(duì)象的原型上添加方法,如 Array, Date。

(5)switch 語句必須帶有 default 分支豫喧。

(6)for 循環(huán)必須使用大括號(hào)石洗。

(7)if 語句必須使用大括號(hào)。


2. JavaScript 代碼中的 “use strict” 是什么意思紧显?

use strict是一種ECMAscript 5 添加的(嚴(yán)格)運(yùn)行模式,這種模式使得 Javascript 在更嚴(yán)格的條件下運(yùn)行,

使JS編碼更加規(guī)范化的模式,消除Javascript語法的一些不合理讲衫、不嚴(yán)謹(jǐn)之處,減少一些怪異行為鸟妙。

默認(rèn)支持的糟糕特性都會(huì)被禁用焦人,比如不能用with,也不能在意外的情況下給全局變量賦值;

全局變量的顯示聲明,函數(shù)必須聲明在頂層重父,不允許在非函數(shù)代碼塊內(nèi)聲明函數(shù),arguments.callee也不允許使用花椭;

消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全,限制函數(shù)中的arguments修改房午,嚴(yán)格模式下的eval函數(shù)的行為和非嚴(yán)格模式的也不相同;


3. 說說嚴(yán)格模式的限制矿辽?

1,變量必須聲明后再使用

2郭厌,函數(shù)的參數(shù)不能有同名屬性袋倔,否則報(bào)錯(cuò)

3,不能使用with語句

4折柠,不能對(duì)只讀屬性賦值宾娜,否則報(bào)錯(cuò)

5,不能使用前綴0表示八進(jìn)制數(shù)扇售,否則報(bào)錯(cuò)

6前塔,不能刪除變量delete prop,會(huì)報(bào)錯(cuò)承冰,只能刪除屬性delete global[prop]

7华弓,eval不會(huì)在它的外層作用域引入變量

8,eval和arguments不能被重新賦值

9困乒,arguments不會(huì)自動(dòng)反映函數(shù)參數(shù)的變化

10寂屏,不能使用arguments.callee

11,禁止this指向全局對(duì)象

12娜搂,不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧

13迁霎,增加了保留字(比如protected、static和interface)

參考文件:https://github.com/ecomfe/spec/blob/master/javascript-style-guide.md


2百宇、運(yùn)算符欧引、運(yùn)算符優(yōu)先級(jí)

1. NaN 是什么?有什么特別之處恳谎?

NaN 屬性是代表非數(shù)字值的特殊值芝此。該屬性用于指示某個(gè)值不是數(shù)字憋肖。可以把 Number 對(duì)象設(shè)置為該值婚苹,來指示其不是數(shù)字值岸更。

提示:請(qǐng)使用 isNaN() 全局函數(shù)來判斷一個(gè)值是否是 NaN 值。

Number.NaN 是一個(gè)特殊值膊升,說明某些算術(shù)運(yùn)算(如求負(fù)數(shù)的平方根)的結(jié)果不是數(shù)字怎炊。方法 parseInt() 和 parseFloat() 在不能解析指定的字符串時(shí)就返回這個(gè)值。對(duì)于一些常規(guī)情況下返回有效數(shù)字的函數(shù)廓译,也可以采用這種方法评肆,用Number.NaN 說明它的錯(cuò)誤情況。

JavaScript 以 NaN 的形式輸出 Number.NaN非区。請(qǐng)注意瓜挽,NaN 與其他數(shù)值進(jìn)行比較的結(jié)果總是不相等的,包括它自身在內(nèi)征绸。因此久橙,不能與 Number.NaN 比較來檢測(cè)一個(gè)值是不是數(shù)字,而只能調(diào)用 isNaN() 來比較管怠。


2. == 與 === 有什么區(qū)別淆衷?

==:運(yùn)算符稱作相等,用來檢測(cè)兩個(gè)操作數(shù)是否相等渤弛,這里的相等定義的非常寬松祝拯,可以允許進(jìn)行類型轉(zhuǎn)換

===:用來檢測(cè)兩個(gè)操作數(shù)是否嚴(yán)格相等

1、對(duì)于string,number等基礎(chǔ)類型她肯,==和===是有區(qū)別的

不同類型間比較佳头,==之比較“轉(zhuǎn)化成同一類型后的值”看“值”是否相等,===如果類型不同辕宏,其結(jié)果就是不等

同類型比較畜晰,直接進(jìn)行“值”比較砾莱,兩者結(jié)果一樣

2瑞筐、對(duì)于Array,Object等高級(jí)類型,==和===是沒有區(qū)別的

3腊瑟、基礎(chǔ)類型與高級(jí)類型聚假,==和===是有區(qū)別的

對(duì)于==,將高級(jí)轉(zhuǎn)化為基礎(chǔ)類型闰非,進(jìn)行“值”比較膘格,因?yàn)轭愋筒煌?==結(jié)果為false


3. console.log(1+"2") 和 console.log(1-"2") 的打印結(jié)果?

// 12 和 1-2

4. 為什么 console.log(0.2+0.1==0.3) 輸出 false 财松?

在JavaScript中的二進(jìn)制的浮點(diǎn)數(shù)0.2和0.6并不是十分精確瘪贱,在他們相加的結(jié)果并非正好等于0.6纱控,而是一個(gè)比較接近的數(shù)字 0.6000000000000001,所以條件判斷結(jié)果為 false菜秦。

那么應(yīng)該怎樣來解決0.2+0.4等于0.6呢? 最好的方法是設(shè)置一個(gè)誤差范圍值甜害,通常稱為”機(jī)器精度“,而對(duì)于Javascript來說球昨,這個(gè)值通常是2^-52,而在ES6中尔店,已經(jīng)為我們提供了這樣一個(gè)

屬性:Number.EPSILON,而這個(gè)值正等于2^-52主慰。這個(gè)值非常非常小嚣州,在底層計(jì)算機(jī)已經(jīng)幫我們運(yùn)算好,并且無限接近0共螺,但不等于0,该肴。這個(gè)時(shí)候我們只要判斷(0.2+0.4)-0.6小于Number.EPSILON,在這個(gè)誤差的范圍內(nèi)就可以判定0.2+0.4===0.6為true璃谨。


5. 請(qǐng)用三元運(yùn)算符(問號(hào)冒號(hào)表達(dá)式)改寫以下代碼:

? ? if(a > 10) {

? ? ? b = a

? ? }else {

? ? ? b = a - 2

? ? }

//b = a > 10? ?? a? :? a-2;

6. 以下代碼輸出的結(jié)果是沙庐?

? ? var a = 1;?

? ? a+++a;? //3

? ? typeof a+2; //number2

7. 以下代碼輸出什么?

? ? var d = a = 3, b = 4

? ? console.log(d) //3

8. 以下代碼輸出什么佳吞?

? ? var d = (a = 3, b = 4)

? ? console.log(d) //4

9. 以下代碼輸出結(jié)果是拱雏?為什么?

? ? var a = 1, b = 2, c = 3;

? ? var val = typeof a + b || c >0? //typeof a? 輸出值為number 底扳,

? ? console.log(val) //number2


? ? var d = 5;

? ? var data = d ==5 && console.log('bb') // bb

? ? console.log(data) //undefined

分析:1.因?yàn)榘凑者\(yùn)算符優(yōu)先級(jí)铸抑,先算&&,

2.然后算 d==5是true

3.然后就繼續(xù) 執(zhí)行右側(cè) log

4.然后返回右側(cè) log 方法的return返回值

5.因?yàn)?log 沒有返回值,所以使用函數(shù)默認(rèn)的衷模,默認(rèn)的是 undefine所以data是 undefined鹊汛。


? ? var data2 = d = 0 || console.log('haha') //haha

? ? console.log(data2) // undefined

解析:var data2 = d = 0 || console.log('haha')等同于var data2 = (d = 0) || [console.log('haha')],先給d賦值為0阱冶,進(jìn)行判斷時(shí)結(jié)果為false刁憋,所以要繼續(xù)進(jìn)行后面的判斷,后面的判斷同上題


? ? var x = !!"Hello" + (!"world", !!"from here!!"); // true+true

? ? console.log(x) //2

解析:var x = !!"Hello" + (!"world", !!"from here!!");等同于var x = 1 + (0, 1);木蹬,進(jìn)行加法時(shí)會(huì)選擇最后一個(gè)數(shù)字進(jìn)行相加

10. 以下代碼輸出結(jié)果是至耻?為什么?

? ? var a = 1;

? ? var b = 3;

? ? console.log( a+++b );? //4

解析:a+++b等同于(a++)+b镊叁,在最終結(jié)果計(jì)算完之后再將a+1

11. 以下代碼輸出的結(jié)果是尘颓?為什么?

? ? console.log(1+1); //2

? ? console.log("2"+"4"); //24

? ? console.log(2+"4"); // 24

? ? console.log(+"4"); 4


3 晦譬、變量疤苹、值、數(shù)據(jù)類型敛腌、數(shù)據(jù)類型轉(zhuǎn)換

1. JavaScript 定義了幾種數(shù)據(jù)類型卧土?哪些是原始類型惫皱?哪些是復(fù)雜類型?null 是對(duì)象嗎尤莺?

原始數(shù)據(jù)類型 (不是對(duì)象且沒有方法):Boolean逸吵、Null、Undefined缝裁、Number扫皱、String、Symbol(ES6 新增)捷绑、BigInt(ES10)

復(fù)雜數(shù)據(jù)類型:Object

Null 類型只有一個(gè)值"null"韩脑。

null 值表示一個(gè)空對(duì)象指針,所以使用typeof會(huì)返回"object";

undefined值是派生于null的粹污,因此會(huì)有null == undefined //true段多。

null轉(zhuǎn)為數(shù)字時(shí),自動(dòng)變成0壮吩。

null表示空值进苍,即該處的值現(xiàn)在為空。調(diào)用函數(shù)時(shí)鸭叙,某個(gè)參數(shù)未設(shè)置任何值觉啊,這時(shí)就可以傳入null,表示該參數(shù)為空沈贝。

無論在何種情況下都沒必要把一個(gè)變量顯式地設(shè)置為undefined杠人,但是只要意在保存對(duì)象的變量還沒有真正保存對(duì)象,就應(yīng)該明確地讓該變量保存null值宋下。

null 有時(shí)會(huì)被當(dāng)作一種對(duì)象類型嗡善,但是這其實(shí)只是語言本身的一個(gè) bug,即對(duì) null 執(zhí)行typeof null 時(shí)會(huì)返回字符串 "object"学歧。實(shí)際上罩引,null 本身是基本類型


2. 對(duì)象類型和原始類型的不同之處?函數(shù)參數(shù)是對(duì)象會(huì)發(fā)生什么問題枝笨?

在 JS 中袁铐,除了原始類型那么其他的都是對(duì)象類型了。對(duì)象類型和原始類型不同的是伺帘,原始類型存儲(chǔ)的是值昭躺,對(duì)象類型存儲(chǔ)的是地址(指針)忌锯。當(dāng)你創(chuàng)建了一個(gè)對(duì)象類型的時(shí)候伪嫁,計(jì)算機(jī)會(huì)在內(nèi)存中幫我們開辟一個(gè)空間來存放值,但是我們需要找到這個(gè)空間偶垮,這個(gè)空間會(huì)擁有一個(gè)地址(指針)张咳。

const a=[]對(duì)于常量a來說帝洪,假設(shè)內(nèi)存地址(指針)為#001,那么在地址#001的位置存放了值[]脚猾,常量a存放了地址(指針)#001葱峡,再看以下代碼

const a=[] ; const b= ab.push(1);

當(dāng)我們將變量賦值給另外一個(gè)變量時(shí),復(fù)制的是原本變量的地址(指針)龙助,也就是說當(dāng)前變量b存放的地址(指針)也是#001砰奕,當(dāng)我們進(jìn)行數(shù)據(jù)修改的時(shí)候程剥,就會(huì)修改存放在地址(指針)#001上的值铅匹,也就導(dǎo)致了兩個(gè)變量的值都發(fā)生了改變是整。

function test(person) {

? person.age = 26

? person = {

? ? name: 'yyy',

? ? age: 30

? }

? return person

}

const p1 = {

? name: 'yck',

? age: 25

}

const p2 = test(p1)

console.log(p1) // -> ?

console.log(p2) // -> ?

對(duì)于以上代碼似芝,你是否能正確的寫出結(jié)果呢扳还?接下來讓我為了解析一番:

? 首先耀鸦,函數(shù)傳參是傳遞對(duì)象指針的副本

? 到函數(shù)內(nèi)部修改參數(shù)的屬性這步材蹬,我相信大家都知道赴魁,當(dāng)前p1的值也被修改了

? 但是當(dāng)我們重新為了person分配了一個(gè)對(duì)象時(shí)就出現(xiàn)了分歧赡鲜,請(qǐng)看下圖

所以最后person擁有了一個(gè)新的地址(指針)空厌,也就和p1沒有任何關(guān)系了,導(dǎo)致了最終兩個(gè)變量的值是不相同的银酬。


3. 怎樣判斷“值”屬于哪種類型嘲更?typeof 是否能正確判斷類型?instanceof 呢揩瞪?instanceof 有什么作用哮内??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的?

1壮韭、值類型的類型判斷用typeof

// 值類型

console.log(typeof(x));? ? // undefined

console.log(typeof(10));?? // number

console.log(typeof('abc')); // string

console.log(typeof(true));? // boolean

//雖然function也是一個(gè)引用類型對(duì)象北发,但是可以通過typeof判斷:

var fn = function() {};

console.log(typeof fn); // function

如何判斷null類型?用 ===:

console.log(null === null); // true

不能用 == 喷屋,因?yàn)椋?/p>

console.log(null == undefined); // true

console.log(null === undefined); // false

2琳拨、引用類型的類型判斷用instanceof

//引用類型

console.log(new String('string') instanceof String); // true

console.log(new Number(10) instanceof Number); // true

console.log(new Boolean(true) instanceof Boolean); // true

console.log(new Array(3,4,5) instanceof Array); // true

console.log([] instanceof Array); // true

var fn = function() {}

console.log(fn instanceof Function); // true

3、Object.prototype.toString.call( ) 方法

Object屯曹。prototype.toString.call()的實(shí)現(xiàn)原理

首先typeof 能夠判斷基本數(shù)據(jù)類型狱庇,但是除了null,typeof null 返回的是object

但是對(duì)于對(duì)象來說typeof不能準(zhǔn)確判斷類型恶耽,typeof 函數(shù)會(huì)返回function密任,除此之外全部都是object,不能準(zhǔn)確判斷類型

instanceof可以判斷復(fù)雜數(shù)據(jù)類型偷俭,基本數(shù)據(jù)類型不可以

instanceof是通過原型鏈來判斷的 浪讳,A instanceof B,在A的原型鏈中層層查找涌萤,是否有原型等于B.prototype淹遵,如果一直找到A的原型鏈的頂端(null口猜,即Object.prototype._proto_),仍然不等于B透揣,那么返回false济炎,否則返回true


4. null,undefined 的區(qū)別辐真?

null表示"沒有對(duì)象"须尚,即該處不應(yīng)該有值。典型用法是:

(1) 作為函數(shù)的參數(shù)侍咱,表示該函數(shù)的參數(shù)不是對(duì)象恨闪。

(2) 作為對(duì)象原型鏈的終點(diǎn)。

Object.getPrototypeOf(Object.prototype)// null

undefined表示"缺少值"放坏,就是此處應(yīng)該有一個(gè)值咙咽,但是還沒有定義。典型用法是:

(1)變量被聲明了淤年,但沒有賦值時(shí)钧敞,就等于undefined。

(2) 調(diào)用函數(shù)時(shí)麸粮,應(yīng)該提供的參數(shù)沒有提供溉苛,該參數(shù)等于undefined。

(3)對(duì)象沒有賦值的屬性弄诲,該屬性的值為undefined愚战。

(4)函數(shù)沒有返回值時(shí),默認(rèn)返回undefined齐遵。

var i;

i // undefined

function f(x){console.log(x)}

f() // undefined

var? o = new Object();

o.p // undefined

var x = f();

x // undefined


5. 說一下 JS 中類型轉(zhuǎn)換的規(guī)則寂玲?

6. 以下代碼的輸出?為什么梗摇?

? ? console.log(a); //undefined

? ? var a = 1;

? ? console.log(b); //報(bào)異常 b is not defined

7. 以下代碼輸出什么拓哟?

? ? var a = typeof 3+4

? ? console.log(a) //number4

8. 以下代碼輸出什么?

? ? var a = typeof typeof 4+4

? ? console.log(a) //string4

分析:typeof 4 輸出為"number"伶授;typeof "number"輸出為"string"


4断序、流程控制語句

1. break 與 continue 有什么區(qū)別?

2. switch...case 語句中的 break 有什么作用糜烹?

3. for...of违诗、 for...in 和 forEach、map 的區(qū)別疮蹦?

4. 寫出如下知識(shí)點(diǎn)的代碼范例:

? ? ① if...else 的用法诸迟;

? ? ② switch...case 的用法;

? ? ③ while 的用法;

? ? ④ do...while 的用法亮蒋;

? ? ⑤ for 遍歷數(shù)組的用法;

? ? ⑥ for...in 遍歷對(duì)象的用法妆毕;

? ? ⑦ break 和 continue 的用法慎玖。

5. 以下代碼輸出什么?

? ? var a = 2

? ? if(a = 1) {

? ? ? console.log("a 等于 1")

? ? }else {

? ? ? console.log("a 不等于 1")

? ? }

輸出為:// a 等于 1

5笛粘、JS 函數(shù)

1. 寫一個(gè)函數(shù)趁怔,返回參數(shù)的平方和?

? ? function sumOfSquares() {

? ? ? // 補(bǔ)全

??????? let arr = Array.from(arguments)

???????? return arr.reduce((result,item)=>{

?????????????? return result += item*item

??????? },0)

? ? }

? ? var result = sumOfSquares(2, 3, 4)

? ? var result2 = sumOfSquares(1, 3)

? ? console.log(result) // 29

? ? console.log(result2) // 10

2. 如下代碼的輸出薪前?為什么润努?

? ? sayName("world");

? ? sayAge(10);

? ? function sayName(name) {

? ? ? console.log("hello ", name);

? ? }

? ? var sayAge = function(age) {

? ? ? console.log(age);

? ? };

// 先輸出:sayAge is not a function,然后再輸出 hello world

3. 如下代碼的輸出示括?為什么铺浇?

? ? var x = 10;

? ? bar()

? ? function bar() {

? ? ? var x = 30;

? ? ? function foo() {

? ? ? ? console.log(x)

? ? ? }

? ? ? foo();

? ? }

//輸出:30

4. 如下代碼的輸出?為什么垛膝?

? ? var x = 10

? ? bar()

? ? function foo() {

? ? ? console.log(x)

? ? }

? ? function bar() {

? ? ? var x = 30

? ? ? foo()

? ? }

輸出: 10

5. 如下代碼的輸出鳍侣?為什么?

? ? var a = 1

? ? function fn1() {

? ? ? function fn3() {

? ? ? ? function fn2() {

? ? ? ? ? console.log(a)

? ? ? ? }

? ? ? ? fn2()

? ? ? ? var a = 4

? ? ? }

? ? ? var a = 2

? ? ? return fn3

? ? }

? ? var fn = fn1()

? ? fn() // 吼拥?undefined

6. 如下代碼的輸出倚聚?為什么?

? ? var a = 1

? ? function fn1() {

? ? ? function fn2() {

? ? ? ? console.log(a)

? ? ? }

? ? ? function fn3() {

? ? ? ? var a = 4

? ? ? ? fn2()

? ? ? }

? ? ? var a = 2

? ? ? return fn3

? ? }

? ? var fn = fn1()

? ? fn() // 2

7. 如下代碼的輸出凿可?為什么惑折?

? ? var a = 1

? ? function fn1() {

? ? ? function fn3() {

? ? ? ? var a = 4

? ? ? ? fn2()

? ? ? }

? ? ? var a = 2

? ? ? return fn3

? ? }

? ? function fn2() {

? ? ? console.log(a)

? ? }

? ? var fn = fn1()

? ? fn() // 1

8. 如下代碼的輸出?為什么枯跑?

? ? var a = 1

? ? var c = {name: "oli", age: 2}

? ? function f1(n) {

? ? ? ++n

? ? }

? ? function f2(obj) {

? ? ? ++obj.age

? ? }

? ? f1(a)

? ? f2(c)

? ? f1(c.age)

? ? console.log(a)

? ? console.log(c)

輸出結(jié)果:

//1

//{age: 3,name: "oli"}

9. 如下代碼的輸出惨驶?為什么?

? ? var obj1 = {a:1, b:2};

? ? var obj2 = {a:1, b:2};

? ? console.log(obj1 == obj2);

? ? console.log(obj1 = obj2);

? ? console.log(obj1 == obj2);

輸出結(jié)果:

// false

//{a: 1,b: 2}

// true

5.1 嵌套函數(shù)敛助、作用域和閉包

1. 閉包是什么敞咧?閉包的作用是什么?閉包有哪些使用場(chǎng)景辜腺?

1休建、變量作用域

要理解閉包,首先要理解javascript的特殊的變量作用域评疗。

變量的作用域無非就兩種:全局變量和局部變量测砂。

javascript語言的特別之處就在于:函數(shù)內(nèi)部可以直接讀取全局變量,但是在函數(shù)外部無法讀取函數(shù)內(nèi)部的局部變量百匆。

注意點(diǎn):在函數(shù)內(nèi)部聲明變量的時(shí)候砌些,一定要使用var命令。如果不用的話,你實(shí)際上聲明的是一個(gè)全局變量存璃!

2仑荐、如何從外部讀取函數(shù)內(nèi)部的局部變量?

出于種種原因纵东,我們有時(shí)候需要獲取到函數(shù)內(nèi)部的局部變量粘招。但是,上面已經(jīng)說過了偎球,正常情況下洒扎,這是辦不到的!只有通過變通的方法才能實(shí)現(xiàn)衰絮。

那就是在函數(shù)內(nèi)部袍冷,再定義一個(gè)函數(shù)。

? ? function f1(){

? ?     var n=999;

? ?     function f2(){

? ?       alert(n); // 999

? ?     }

? ?   }

在上面的代碼中猫牡,函數(shù)f2就被包括在函數(shù)f1內(nèi)部胡诗,這時(shí)f1內(nèi)部的所有局部變量,對(duì)f2都是可見的淌友。但是反過來就不行乃戈,f2內(nèi)部的局部變量,對(duì)f1就是不可見的亩进。

這就是Javascript語言特有的"鏈?zhǔn)阶饔糜?結(jié)構(gòu)(chain scope)症虑,

子對(duì)象會(huì)一級(jí)一級(jí)地向上尋找所有父對(duì)象的變量。所以归薛,父對(duì)象的所有變量谍憔,對(duì)子對(duì)象都是可見的,反之則不成立主籍。

既然f2可以讀取f1中的局部變量习贫,那么只要把f2作為返回值,我們不就可以在f1外部讀取它的內(nèi)部變量了嗎千元!

3苫昌、閉包的概念

上面代碼中的f2函數(shù),就是閉包幸海。

各種專業(yè)文獻(xiàn)的閉包定義都非常抽象祟身,我的理解是: 閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。

由于在javascript中物独,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量袜硫,所以說,閉包可以簡(jiǎn)單理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)“挡篓。

所以婉陷,在本質(zhì)上帚称,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來的橋梁。

4秽澳、閉包的用途

閉包可以用在許多地方闯睹。它的最大用處有兩個(gè),一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量担神,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中楼吃,不會(huì)在f1調(diào)用后被自動(dòng)清除。

為什么會(huì)這樣呢杏瞻?原因就在于f1是f2的父函數(shù)所刀,而f2被賦給了一個(gè)全局變量衙荐,這導(dǎo)致f2始終在內(nèi)存中捞挥,而f2的存在依賴于f1,因此f1也始終在內(nèi)存中忧吟,不會(huì)在調(diào)用結(jié)束后砌函,被垃圾回收機(jī)制(garbage collection)回收。

這段代碼中另一個(gè)值得注意的地方溜族,就是"nAdd=function(){n+=1}"這一行讹俊,首先在nAdd前面沒有使用var關(guān)鍵字,因此nAdd是一個(gè)全局變量煌抒,而不是局部變量仍劈。其次,nAdd的值是一個(gè)匿名函數(shù)(anonymous function)寡壮,而這個(gè)匿名函數(shù)本身也是一個(gè)閉包贩疙,所以nAdd相當(dāng)于是一個(gè)setter,可以在函數(shù)外部對(duì)函數(shù)內(nèi)部的局部變量進(jìn)行操作况既。

5这溅、閉包的優(yōu)點(diǎn)

(1)邏輯連續(xù),當(dāng)閉包作為另一個(gè)函數(shù)調(diào)用參數(shù)時(shí)棒仍,避免脫離當(dāng)前邏輯而單獨(dú)編寫額外邏輯悲靴。

(2)方便調(diào)用上下文的局部變量。

(3)加強(qiáng)封裝性莫其,是第2點(diǎn)的延伸癞尚,可以達(dá)到對(duì)變量的保護(hù)作用。

6乱陡、使用閉包的注意點(diǎn)(缺點(diǎn))

(1)由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中否纬,內(nèi)存消耗很大,所以不能濫用閉包蛋褥,否則會(huì)造成網(wǎng)頁的性能問題临燃,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前膜廊,將不使用的局部變量全部刪除乏沸。

(2)閉包會(huì)在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值爪瓜。所以蹬跃,如果你把父函數(shù)當(dāng)作對(duì)象(object)使用,把閉包當(dāng)作它的公用方法(Public Method)铆铆,把內(nèi)部變量當(dāng)作它的私有屬性(private value)蝶缀,這時(shí)一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值薄货。

7翁都、閉包的特性

(1)作為函數(shù)變量的一個(gè)引用。當(dāng)函數(shù)返回時(shí)谅猾,其處于激活狀態(tài)柄慰。

(2)閉包就是當(dāng)一個(gè)函數(shù)返回時(shí),并沒有釋放資源的棧區(qū)税娜。

8坐搔、閉包對(duì)頁面的影響

通過使用閉包,我們可以做很多事情敬矩。比如模擬面向?qū)ο蟮拇a風(fēng)格概行;更優(yōu)雅、更簡(jiǎn)潔的表達(dá)出代碼弧岳;在某些方面提升代碼的執(zhí)行效率凳忙。

9、閉包的工作原理

因?yàn)殚]包只有在被調(diào)用時(shí)才執(zhí)行操作缩筛,所以它可以被用來定義控制結(jié)構(gòu)消略。多個(gè)函數(shù)可以使用同一個(gè)環(huán)境,這使得他們可以通過改變那個(gè)環(huán)境相互交流瞎抛。

10艺演、使用場(chǎng)景

(1)采用函數(shù)引用方式的setTimeout調(diào)用。 例子

(2)將函數(shù)關(guān)聯(lián)到對(duì)象的實(shí)例方法桐臊。

(3)封裝相關(guān)的功能集胎撤。


2. 使用遞歸完成 1 到 100 的累加?

function add(i) {

if(i==1)

return i;

else

return i+add(i-1);

}

var? s=add(100);

console.log(s) //5050


3. 談?wù)劺厥諜C(jī)制的方式及內(nèi)存管理断凶?

回收機(jī)制方式

1伤提、定義和用法:垃圾回收機(jī)制(GC:Garbage Collection),執(zhí)行環(huán)境負(fù)責(zé)管理代碼執(zhí)行過程中使用的內(nèi)存。

2认烁、原理:垃圾收集器會(huì)定期(周期性)找出那些不在繼續(xù)使用的變量肿男,然后釋放其內(nèi)存介汹。但是這個(gè)過程不是實(shí)時(shí)的,因?yàn)槠溟_銷比較大舶沛,所以垃圾回收器會(huì)按照固定的時(shí)間間隔周期性的執(zhí)行嘹承。

3、實(shí)例如下:

function fn1() {

var obj = {name: ‘hanzichi’, age: 10};

}

function fn2() {

var obj = {name:‘hanzichi’, age: 10};

return obj;

}

var a = fn1();

var b = fn2();

fn1中定義的obj為局部變量如庭,而當(dāng)調(diào)用結(jié)束后叹卷,出了fn1的環(huán)境,那么該塊內(nèi)存會(huì)被js引擎中的垃圾回收器自動(dòng)釋放坪它;在fn2被調(diào)用的過程中骤竹,返回的對(duì)象被全局變量b所指向,所以該塊內(nèi)存并不會(huì)被釋放往毡。

4蒙揣、垃圾回收策略:標(biāo)記清除(較為常用)和引用計(jì)數(shù)。

標(biāo)記清除:

定義和用法:當(dāng)變量進(jìn)入環(huán)境時(shí)卖擅,將變量標(biāo)記"進(jìn)入環(huán)境"鸣奔,當(dāng)變量離開環(huán)境時(shí)墨技,標(biāo)記為:“離開環(huán)境”惩阶。某一個(gè)時(shí)刻,垃圾回收器會(huì)過濾掉環(huán)境中的變量扣汪,以及被環(huán)境變量引用的變量断楷,剩下的就是被視為準(zhǔn)備回收的變量。

到目前為止崭别,IE冬筒、Firefox、Opera茅主、Chrome舞痰、Safari的js實(shí)現(xiàn)使用的都是標(biāo)記清除的垃圾回收策略或類似的策略,只不過垃圾收集的時(shí)間間隔互不相同诀姚。

引用計(jì)數(shù):

定義和用法:引用計(jì)數(shù)是跟蹤記錄每個(gè)值被引用的次數(shù)响牛。

基本原理:就是變量的引用次數(shù),被引用一次則加1赫段,當(dāng)這個(gè)引用計(jì)數(shù)為0時(shí)呀打,被視為準(zhǔn)備回收的對(duì)象。

內(nèi)存管理

1糯笙、什么時(shí)候觸發(fā)垃圾回收贬丛?

垃圾回收器周期性運(yùn)行,如果分配的內(nèi)存非常多给涕,那么回收工作也會(huì)很艱巨豺憔,確定垃圾回收時(shí)間間隔就變成了一個(gè)值得思考的問題额获。

IE6的垃圾回收是根據(jù)內(nèi)存分配量運(yùn)行的,當(dāng)環(huán)境中的變量恭应,對(duì)象咪啡,字符串達(dá)到一定數(shù)量時(shí)觸發(fā)垃圾回收。垃圾回收器一直處于工作狀態(tài)暮屡,嚴(yán)重影響瀏覽器性能撤摸。

IE7中线得,垃圾回收器會(huì)根據(jù)內(nèi)存分配量與程序占用內(nèi)存的比例進(jìn)行動(dòng)態(tài)調(diào)整掉冶,開始回收工作。

2凌蔬、合理的GC方案:(1)莺掠、遍歷所有可訪問的對(duì)象; (2)衫嵌、回收已不可訪問的對(duì)象。

3彻秆、GC缺陷:(1)楔绞、停止響應(yīng)其他操作;

4唇兑、GC優(yōu)化策略:(1)酒朵、分代回收(Generation GC);(2)、增量GC


4. 談?wù)勀銓?duì) JS 執(zhí)行上下文棧和作用域鏈的理解扎附?

一蔫耽、JS執(zhí)行上下文

執(zhí)行上下文就是當(dāng)前 JavaScript 代碼被解析和執(zhí)行時(shí)所在環(huán)境的抽象概念, JavaScript 中運(yùn)行任何的代碼都是在執(zhí)行上下文中運(yùn)行留夜。

執(zhí)行上下文類型分為:全局執(zhí)行上下文和函數(shù)執(zhí)行上下文匙铡。執(zhí)行上下文創(chuàng)建過程中,需要做以下幾件事:

(1)創(chuàng)建變量對(duì)象:首先初始化函數(shù)的參數(shù)arguments碍粥,提升函數(shù)聲明和變量聲明鳖眼。

(2)創(chuàng)建作用域鏈(Scope Chain):在執(zhí)行期上下文的創(chuàng)建階段,作用域鏈?zhǔn)窃谧兞繉?duì)象之后創(chuàng)建的嚼摩。

(3)確定this的值钦讳,即 ResolveThisBinding

二、作用域

  作用域就是變量和函數(shù)的可訪問范圍低斋,控制這個(gè)變量或者函數(shù)可訪問行和生命周期蜂厅。

  作用域有兩種工作模型:詞法作用域和動(dòng)態(tài)作用域,JS采用的是詞法作用域工作模型膊畴,詞法作用域意味著作用域是由書寫代碼時(shí)變量和函數(shù)聲明的位置決定的掘猿。( with 和 eval 能夠修改詞法作用域,但是不推薦使用唇跨,對(duì)此不做特別說明)

  在 js 中是詞法作用域稠通,意思就是你的變量函數(shù)的作用域是由你的編碼中的位置決定的衬衬,當(dāng)然可以通過 apply、call改橘、 bind 等函數(shù)進(jìn)行修改滋尉。

  在 ES6 之前,js 中的作用域分為兩種:函數(shù)作用域和全局作用域飞主,現(xiàn)在作用域分為:全局作用域狮惜、函數(shù)作用域、塊級(jí)作用域碌识。

  全局作用域顧名思義碾篡,瀏覽器下就是 window ,作用域鏈的頂級(jí)就是它筏餐,那么只要不是被函數(shù)包裹的變量或者函數(shù)开泽,它的作用域就是全局。

  而函數(shù)作用域魁瞪,就是在函數(shù)的體內(nèi)聲明的變量穆律、函數(shù)及函數(shù)的參數(shù),它們的作用域都是在這個(gè)函數(shù)內(nèi)部导俘。

三峦耘、JS執(zhí)行上下文棧(后面簡(jiǎn)稱執(zhí)行棧)

  執(zhí)行棧,也叫做調(diào)用棧趟畏,具有 LIFO (后進(jìn)先出) 結(jié)構(gòu)贡歧,用于存儲(chǔ)在代碼執(zhí)行期間創(chuàng)建的所有執(zhí)行上下文滩租。

規(guī)則如下:

  首次運(yùn)行JavaScript代碼的時(shí)候,會(huì)創(chuàng)建一個(gè)全局執(zhí)行的上下文并Push到當(dāng)前的執(zhí)行棧中赋秀,每當(dāng)發(fā)生函數(shù)調(diào)用,引擎都會(huì)為該函數(shù)創(chuàng)建一個(gè)新的函數(shù)執(zhí)行上下文并Push當(dāng)前執(zhí)行棧的棧頂律想。

當(dāng)棧頂?shù)暮瘮?shù)運(yùn)行完成后猎莲,其對(duì)應(yīng)的函數(shù)執(zhí)行上下文將會(huì)從執(zhí)行棧中Pop出,上下文的控制權(quán)將移動(dòng)到當(dāng)前執(zhí)行棧的下一個(gè)執(zhí)行上下文技即。

四著洼、作用域鏈

  我們知道函數(shù)在執(zhí)行時(shí)是有個(gè)執(zhí)行棧,在函數(shù)執(zhí)行的時(shí)候會(huì)創(chuàng)建執(zhí)行環(huán)境而叼,也就是執(zhí)行上下文身笤,在上下文中有個(gè)大對(duì)象,保存執(zhí)行環(huán)境定義的變量和函數(shù)葵陵,在使用變量的時(shí)候液荸,就會(huì)訪問這個(gè)大對(duì)象,這個(gè)對(duì)象會(huì)隨著函數(shù)的調(diào)用而創(chuàng)建脱篙,函數(shù)執(zhí)行結(jié)束出棧而銷毀娇钱,那么這些大對(duì)象組成一個(gè)鏈伤柄,就是作用域鏈。那么函數(shù)內(nèi)部未定義的變量文搂,就會(huì)順著作用域鏈向上查找适刀,一直找到同名的屬性。


5. 如下代碼輸出多少煤蹭?如果想輸出 3笔喉,那如何改造代碼?

? ? var fnArr = [];

? ? for(var i=0; i<10; i++) {

? ? ? fnArr[i] =? function() {

? ? ? ? return i

? ? ? };

? ? }

? ? console.log(fnArr[3]())

//輸出10

//如果想輸出 3 方法一

var fnArr = [];

for (var i = 0; i < 10; i ++) {

? (function(i){

? ? fnArr[i] =? function(){

? ? ? return i

? ? };

? })(i)

}

console.log( fnArr[3]() )

//方法二

var fnArr = [];

for (var i = 0; i < 10; i ++) {

? fnArr[i] =? (function(j){

? ? return function(){

? ? ? return j

? ? }

? })(i)

}

console.log( fnArr[3]() )

//方法三

var fnArr = []

for (let i = 0; i < 10; i ++) {

? fnArr[i] =? function(){

? ? return i

? }

}

console.log( fnArr[3]() )


6. 封裝一個(gè) Car 對(duì)象硝皂。

? ? var Car = (function() {

? ? ? var speed = 0;

? ? ? // 補(bǔ)充

? ? ? return {

? ? ? ? setSpeed: setSpeed,

? ? ? ? getSpeed: getSpeed,

? ? ? ? speedUp: speedUp,

? ? ? ? speedDown: speedDown

? ? ? }

? ? })()

? ? Car.setSpeed(30)

? ? Car.getSpeed() // 30

? ? Car.speedUp()

? ? Car.getSpeed() // 31

? ? Car.speedDown()

? ? Car.getSpeed() // 30

實(shí)現(xiàn):

var Car = (function(){

? var speed = 0;

? function setSpeed(val){

? ? speed = val

? ? return speed


? }

? function getSpeed(){

? ? console.log(speed)

? ? return speed


? }

? function speedUp(){

? ? ? speed++

? }

? function speedDown(){

? ? ? speed--

? }

? return {

? ? ? setSpeed: setSpeed,

? ? ? getSpeed: getSpeed,

? ? ? speedUp: speedUp,

? ? ? speedDown: speedDown

? }

})()

Car.setSpeed(30)

Car.getSpeed() //30

Car.speedUp()

Car.getSpeed() //31

Car.speedDown()

Car.getSpeed()? //30


7. 如下代碼輸出多少然遏?如何連續(xù)輸出 0, 1, 2, 3, 4?

? ? for(var i=0; i<5; i++) {

? ? ? setTimeout(function() {

? ? ? ? console.log("delayer:" + i)

? ? ? }, 0)

? ? }

// 輸出5個(gè)delayer:5

//改造 方法一

for(var i=0; i<5; i++){

? (function(i){

? ? setTimeout(function(){

? ? ? console.log('delayer:' + i )

? ? }, 0)

? })(i)

}

//方法二

for(var i=0; i<5; i++){

? setTimeout((function(i){

? ? return function(){

? ? ? console.log('delayer:' + i )

? ? }

? })(i), 0)

}

//方法三

for(let i=0; i<5; i++){

? setTimeout(function(){

? ? console.log('delayer:' + i )

? }, 0)

}


8. 如下代碼輸出多少吧彪?

? ? function makeCounter() {

? ? ? var count = 0

? ? ? return function() {

? ? ? ? return count++

? ? ? };

? ? }

? ? var counter = makeCounter()

? ? var counter2 = makeCounter();

? ? console.log(counter()) // 0

? ? console.log(counter()) // 1

? ? console.log(counter2()) // 0

? ? console.log(counter2()) // 1


6待侵、JS 數(shù)組

1. 寫一個(gè)函數(shù) squireArr,其參數(shù)是一個(gè)數(shù)組姨裸,作用是把數(shù)組中的每一項(xiàng)變?yōu)樵档钠椒健?/b>

? ? var arr = [3, 4, 6]

? ? function squireArr(arr) {

? ? ? // 補(bǔ)全

??????? window.arr?=??arr.map(function(a){return?a*a})

? ? }

? ? squireArr(arr)

? ? console.log(arr) // [9, 16, 36]

2. 寫一個(gè)函數(shù) squireArr秧倾,其參數(shù)是一個(gè)數(shù)組,返回一個(gè)新的數(shù)組傀缩,新數(shù)組中的每一項(xiàng)是原數(shù)組

?? 對(duì)應(yīng)值的平方那先,原數(shù)組不變。

? ? var arr = [3, 4, 6]

? ? function squireArr(arr) {

? ? ? // 補(bǔ)全

?????? return arr.map(function(a){returna*a});

? ? }

? ? var arr2 = squireArr(arr)

? ? console.log(arr) // [3, 4, 6]

? ? console.log(arr2) // [9, 16, 36]


3. 遍歷 company 對(duì)象赡艰,輸出里面每一項(xiàng)的值售淡。

? ? var company = {

? ? ? name: "qdywxs",

? ? ? age: 3,

? ? ? sex: "男"

? ? }

代碼:

for(key in company) {

? console.log(company[key]);

}

4. 遍歷數(shù)組,打印數(shù)組里的每一項(xiàng)的平方慷垮。

? ? var arr = [3, 4, 5]

?? arr.forEach((ite)=>{console.log(ite*ite)});


7揖闸、JS 對(duì)象

1. 介紹 JS 有哪些內(nèi)置對(duì)象?

時(shí)間對(duì)象date料身,字符串對(duì)象string汤纸,數(shù)學(xué)對(duì)象Math,數(shù)值對(duì)象Number芹血,數(shù)組對(duì)象Array贮泞,函數(shù)對(duì)象function, 正則表達(dá)式對(duì)象RegExp,函數(shù)參數(shù)集合arguments,布爾對(duì)象Boolean,錯(cuò)誤對(duì)象Error,基礎(chǔ)對(duì)象Object

2. 以下代碼輸出什么幔烛?

? ? var name = "sex"

? ? var company = {

? ? ? name: "qdywxs",

? ? ? age: 3,

? ? ? sex: "男"

? ? }

? ? console.log(company[name]) //男

3. 以下代碼輸出什么啃擦?

? ? var name = "sex"

? ? var company = {

? ? ? name: "qdywxs",

? ? ? age: 3,

? ? ? sex: "男"

? ? }

? ? console.log(company.name) // qdywxs


7.1 ES3 數(shù)組方法

1. 數(shù)組的哪些 API 會(huì)改變?cè)瓟?shù)組?

修改原數(shù)組的API有:splice()饿悬,reverse()令蛉,fill(),copyWithin()乡恕,sort()言询,push()俯萎,pop(),unshift()运杭,shift()

不修改原數(shù)組的有:slice()夫啊,map(),forEach()辆憔,every()撇眯,filter(),reduce()虱咧,entry()熊榛,entries(),find()

2. 寫一個(gè)函數(shù)腕巡,操作數(shù)組玄坦,返回一個(gè)新數(shù)組,新數(shù)組中只包含正數(shù)绘沉。

? ? function filterPositive(arr) {

? ? ? // 補(bǔ)全

?????? var newArr = []

??? for(var i = 0; i < arr.length; i++ ){

????? if (typeof arr[i] === 'number') {

? ????? if (arr[i] > 0) [

? ? ????? newArr.push(arr[i])

? ????? ]

? ? ? }

??? }

??? return newArr

? ? }

? ? var arr = [3, -1, 2, true]

? ? filterPositive(arr)

? ? console.log(filterPositive(arr)) // [3, 2]


3. 補(bǔ)全代碼煎楣,實(shí)現(xiàn)數(shù)組按姓名、年紀(jì)车伞、任意字段排序择懂。

? ? var users = [

? ? ? {name: "John", age: 20, company: "Baidu"},

? ? ? {name: "Pete", age: 18, company: "Alibaba"},

? ? ? {name: "Ann", age: 19, company: "Tecent"}

? ?? ]

????? function byField(field){
???????????? return function(user1, user2){

? ? ? ? ? ? ? ? ? return user1[field] > user2[field]//因?yàn)閒ield是字符串,所以不能用.來訪問

??????? }

? ? }

? ? users.sort(byField("age"))

? ? users.sort(byField("company"))


4. 用 splice 函數(shù)分別實(shí)現(xiàn) push另玖、pop困曙、shift、unshift 方法谦去。

?? 如:

? ? function push(arr, value) {

? ? ? arr.splice(arr.length, 0, value)

? ? ? return arr.length

? ? }

?? function pop(arr) {

? ? ? return arr.splice(arr.length-1,1);

? ? }

?? function shift(arr) {

? ? ? return arr.splice(0,1);

? ? }

? function unshift(arr,value) {

? ? ? return arr.splice(arr.length-1,1,value);

? ? }

? ? var arr = [3, 4, 5]

? ? arr.push(10) // arr 變成 [3, 4, 5, 10]慷丽,返回 4。

??? arr.pop(10) // arr 變成 [3, 4]哪轿,返回 5盈魁。

??? arr.shift() //3

??? arr.unshift() //4


7.2 ES5 數(shù)組方法

1. for...of、 for...in 和 forEach窃诉、map 的區(qū)別?

1赤套、for..in

for..in可以將JavaScript中的對(duì)象的屬性依次循環(huán)出來飘痛,當(dāng)for..in作用于數(shù)組時(shí)得到的是該元素的下標(biāo),且該下標(biāo)是一個(gè)String對(duì)象而不是一個(gè)Number對(duì)象容握。(注意:for..in實(shí)際上是歷史遺留問題宣脉,其遍歷的實(shí)際上是對(duì)象的屬性,之所以能夠遍歷數(shù)組剔氏,是因?yàn)閿?shù)組實(shí)際上是一個(gè)對(duì)象塑猖,而其屬性就是下標(biāo)竹祷,所以使用for..in遍歷數(shù)組得到的下標(biāo)是String類型)

for..in的問題在于,當(dāng)我們?yōu)橐粋€(gè)數(shù)組添加了一個(gè)不是數(shù)字下標(biāo)的屬性時(shí)羊苟,遍歷數(shù)組時(shí)會(huì)將這個(gè)屬性當(dāng)做是下標(biāo)遍歷出來:

let a = ['A', 'B', 'C'];

a.name = 'Hello';

for (let x in a) {

? ? console.log(x); // '0', '1', '2', 'name'

}

2塑陵、for..of

for..of就是為了遍歷集合而專門設(shè)計(jì)的,它只遍歷數(shù)組的元素:

let a = ['A', 'B', 'C'];

a.name = 'Hello';

for (let x of a) {

? ? console.log(x); // 'A', 'B', 'C'

}

并且當(dāng)for..of直接遍歷對(duì)象時(shí)會(huì)報(bào)錯(cuò):

let obj = {

? ? ? ? ? name:'123123',

? ? ? ? ? age:15

? ? ? }

for (let cc of obj) {//Uncaught TypeError: obj is not iterable

? ? ? console.log(cc)

}

for..of用于遍歷對(duì)象需要使用Object.keys()才能正確遍歷其屬性(而Object.keys()方法實(shí)際上是將對(duì)象的屬性鍵值以數(shù)組的對(duì)象返回了回來蜡励,實(shí)際上也是遍歷數(shù)組令花。所以說for..of不能遍歷對(duì)象其實(shí)也沒有錯(cuò)):

let obj = {

? ? ? ? ? name:'123123',

? ? ? ? ? age:15

? ? ? }

for (let cc of Object.keys(obj)) {

? ? ? console.log(cc)//name,age

}

3、forEach

forEach是Iterable的內(nèi)置方法凉倚,是一個(gè)高階函數(shù)兼都,其接受一個(gè)函數(shù)作為參數(shù),每次迭代就回調(diào)該函數(shù)稽寒。是遍歷Iterable(Array,Map,Set)最好的方式(但是相對(duì)于for..of有一個(gè)壞處就是不能通過break退出循環(huán)):

let arr = ['A', 'B', 'C'];

arr.forEach(function (element, index, array) {

? ? // element: 指向當(dāng)前元素的值

? ? // index: 指向當(dāng)前索引

? ? // array: 指向Array對(duì)象本身

? ? console.log(element + ', index = ' + index);

});

let set = new Set(['A', 'B', 'C']);

set.forEach(function (element, sameElement, set) {

? ? //Set沒有索引扮碧,因此回調(diào)函數(shù)的前兩個(gè)參數(shù)都是元素本身

? ? console.log(element);

});

let map = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);

map.forEach(function (value, key, map) {

? ? //map接受的參數(shù)為值,鍵和其自身

? ? console.log(value);

});


2.? 如何消除一個(gè)數(shù)組里面重復(fù)的元素杏糙?

1.兼容Set 和?Array.from() 的環(huán)境下:

??? let orderedArray = Array.from(new Set(myArray));

??? var myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'];

??? var myOrderedArray = myArray.reduce(function (accumulator, currentValue) {

? ? ?? if (accumulator.indexOf(currentValue) === -1) {

? ? ? ? ?? accumulator.push(currentValue);

?????? }

? ? ? return accumulator

?? }, [])

?? console.log(myOrderedArray);

? 2.利用arr.reduce()去重

???? //簡(jiǎn)單去重

??? let arr = [1,2,3,4,4,1]

??? let newArr = arr.reduce((pre,cur)=>{

? ????? if(!pre.includes(cur)){

? ? ????? return pre.concat(cur)

? ????? }else{

? ? ????? return pre

? ????? }

??? },[])

??? console.log(newArr);// [1, 2, 3, 4]

??? 3.擴(kuò)展運(yùn)算符數(shù)組去重

??? var arr = [1,2,3,4,5,2,3,1];

??? var set =?new Set(arr);

??? var newArr = [...set ];

??? 4.去重?cái)?shù)組并排序

??? let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];

??? let result = arr.sort().reduce((init, current) => {

? ????? if(init.length === 0 || init[init.length-1] !== current) {

? ? ? ????? init.push(current);

? ????? }

? ????? return init;

??? }, []);

??? console.log(result); //[1,2,3,4,5]


3. 判斷一個(gè)變量是否是數(shù)組芬萍,有哪些辦法?

1搔啊、instanceof

function isArray (obj) {

? return obj instanceof Array;

}

2柬祠、Array對(duì)象的 isArray方法

function isArray (obj) {

? return Array.isArray(obj);

}

3、Object.prototype.toString

function isArray (obj) {

? return Object.prototype.toString.call(obj) === '[object Array]';

}


4. ["1", "2", "3"].map(parseInt) 答案是多少负芋?

輸出:[ 1,NaN,NaN ]

解析:

map方法

引入MDN的解釋漫蛔,map()方法創(chuàng)建一個(gè)新數(shù)組,其結(jié)果是該數(shù)組中的每個(gè)元素都調(diào)用一個(gè)提供的函數(shù)后返回的結(jié)果旧蛾。

var arr = [1, 2, 3];

var arr1 = arr.map(x => x+1);

console.log(arr1); // 2,3,4

可以看出map方法中接受一個(gè)函數(shù)function莽龟,用來處理遍歷數(shù)組中的每一個(gè)元素。

new_array = [].map(function callback(currentValue[,index[,array]]){ // Return element for new_array }[, thisArg]);

這個(gè)callback一共可以接收三個(gè)參數(shù)锨天,其中第一個(gè)參數(shù)代表當(dāng)前被處理的元素毯盈,第二個(gè)參數(shù)代表該元素的索引。

parseInt函數(shù)

parseInt是用來解析字符串病袄,使字符串成為指定基數(shù)的整數(shù)搂赋,parseInt的基本語法,

parseInt(string, radix)

接收兩個(gè)參數(shù)益缠,第一個(gè)表示被處理的值(字符串)脑奠,第二個(gè)表示為解析時(shí)的基數(shù)。radix是一個(gè)介于2-36之間的整數(shù)幅慌,返回解析后的整數(shù)值宋欺。 如果被解析參數(shù)的第一個(gè)字符無法被轉(zhuǎn)化成數(shù)值類型,則返回 NaN

praseInt('111') // 111

parseInt('111', 0) // 111

// radix為0時(shí),且string參數(shù)不以“0x”和“0”開頭時(shí)齿诞,按照10為基數(shù)處理

parseInt('111', 1) // NaN 【2 <= radix <= 36】

parseInt('111', 2) // 7

從上面可以看出根據(jù)指定不同的radix酸休,返回不同的值。

radix參數(shù)為n將會(huì)把第一個(gè)參數(shù)看作是一個(gè)數(shù)的n進(jìn)制表示祷杈,而返回的值則是十進(jìn)制斑司。

parseInt('123', 5) // 將'123'看作5進(jìn)制數(shù),返回十進(jìn)制數(shù)38 => 1*5^2 + 2*5^1 + 3*5^0 = 38

下面我們來分析一下[‘1’, ‘2’, ‘3’].map(parseInt);

parseInt(‘1’, 0); // radix為0時(shí)吠式,使用默認(rèn)的10進(jìn)制陡厘。

parseInt(‘2’, 1); // radix值在2-36,無法解析特占,返回NaN

parseInt(‘3’, 2); // 基數(shù)為2糙置,2進(jìn)制數(shù)表示的數(shù)中,最大值小于3是目,無法解析谤饭,返回NaN

map函數(shù)返回的是一個(gè)數(shù)組,所以最后結(jié)果為[1, NaN, NaN]懊纳。


5. 取數(shù)組的最大值(ES5揉抵、ES6)?

1.apply()應(yīng)用某一對(duì)象的一個(gè)方法嗤疯,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象

var max = Math.max.apply(null,arr);

console.log(max)

由于max()里面參數(shù)不能為數(shù)組冤今,所以借助apply(funtion,args)方法調(diào)用Math.max(),function為要調(diào)用的方法茂缚,args是數(shù)組對(duì)象戏罢,當(dāng)function為null時(shí),默認(rèn)為上文,即相當(dāng)于apply(Math.max,arr)

2.call()調(diào)用一個(gè)對(duì)象的一個(gè)方法脚囊,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象

var max1 = Math.max.call(null,7,2,0,-3,5)

console.log(max1)

call()與apply()類似龟糕,區(qū)別是傳入?yún)?shù)的方式不同,apply()參數(shù)是一個(gè)對(duì)象和一個(gè)數(shù)組類型的對(duì)象悔耘,call()參數(shù)是一個(gè)對(duì)象和參數(shù)列表

3.sort()+reverse()

//sort()排序默認(rèn)為升序讲岁,reverse()將數(shù)組掉個(gè)

var max3 = arr.sort().reverse()[0];

console.log(max3)

4.sort()

//b-a從大到小,a-b從小到大

var max2 = arr.sort(function(a,b){

? return b-a;

})[0];

console.log(max2);

5.es6擴(kuò)展語法

??? var arr = [1, 2, 3];

??? var max = Math.max(...arr);


6. 實(shí)現(xiàn)一個(gè) reduce 函數(shù)衬以,作用和原生的 reduce 類似下面的例子缓艳。

?? Ex:

? ? var sum = reduce([1, 2, 3], function(memo, num) {return memo + num;}, 0); => 6

如下:

function newReduce(arr, iteratee, initValue){

? var tmpArr = (initValue === undefined ? [] : [initValue]).concat(arr);//判斷是否有原始值

? while(tmpArr.length > 1){

? ? tmpArr.splice(0, 2, iteratee(tmpArr[0], tmpArr[1]));

? }

? return tmpArr[0];

}

var sum = newReduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);

console.log(sum);


7. 怎樣用原生 JS 將一個(gè)多維數(shù)組拍平?
方法一:concat

function flatten(arr) {

? ? var result = [];

? ? arr.forEach(function(value, index, array) {

? ? ? ? if(Array.isArray(value)) {

? ? ? ? ? ? result = result.concat(flatten(value));

? ? ? ? } else {

? ? ? ? ? ? result = result.concat(value);

? ? ? ? }

? ? });

? ? return result;

}

方法二:閉包

function flatten(arr) {

? ? var result = [];

? ? function _flatten(arr) {

? ? ? ? arr.forEach(function(value, index, array){

? ? ? ? ? ? if(Array.isArray(value)) {

? ? ? ? ? ? ? ? _flatten(value);

? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? result.push(value);

? ? ? ? ? ? }

? ? ? ? });

? ? }

? ? _flatten(arr);

? ? return result;

}

方法三:reduce

function flatten(arr) {

? return arr.reduce(function(a, b){

? ? ? if(Array.isArray(b)) {

? ? ? ? ? return a.concat(flatten(b));

? ? ? } else {

? ? ? ? ? return a.concat(b);

? ? ? }

? },[]);

}

function newFlatten(arr){

? return arr.reduce(function(initArr, currentArr){

? ? ? return initArr.concat(Array.isArray(currentArr) ? newFlatten(currentArr) : [currentArr]);

? } ,[]);

}

var result = newFlatten([1, [2], [3, [[4]]]]);

console.log(result);

?console.log(flat(array)) // [1, 2, 3, 4, 5]


8泄鹏、面向?qū)ο缶幊?/h3>

8.1 對(duì)象構(gòu)造函數(shù)

1. new 的原理是什么郎任?通過 new 的方式創(chuàng)建對(duì)象和通過字面量創(chuàng)建有什么區(qū)別?

new的原理:

創(chuàng)建一個(gè)新對(duì)象备籽。

這個(gè)新對(duì)象會(huì)被執(zhí)行[[原型]]連接。

將構(gòu)造函數(shù)的作用域賦值給新對(duì)象,即this指向這個(gè)新對(duì)象.

如果函數(shù)沒有返回其他對(duì)象车猬,那么new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象霉猛。

function new(func) {

? ? lat target = {};

? ? target.__proto__ = func.prototype;

? ? let res = func.call(target);

? ? if (typeof(res) == "object" || typeof(res) == "function") {

? ? return res;

? ? }

? ? return target;

}

字面量創(chuàng)建對(duì)象,不會(huì)調(diào)用 Object構(gòu)造函數(shù), 簡(jiǎn)潔且性能更好;

new Object() 方式創(chuàng)建對(duì)象本質(zhì)上是方法調(diào)用珠闰,涉及到在proto鏈中遍歷該方法惜浅,當(dāng)找到該方法后,又會(huì)生產(chǎn)方法調(diào)用必須的 堆棧信息伏嗜,方法調(diào)用結(jié)束后坛悉,還要釋放該堆棧,性能不如字面量的方式承绸。

通過對(duì)象字面量定義對(duì)象時(shí)裸影,不會(huì)調(diào)用Object構(gòu)造函數(shù)。


2. Object.create 有什么作用军熏?

語法:

Object.create(proto, [propertiesObject])

//方法創(chuàng)建一個(gè)新對(duì)象轩猩,使用現(xiàn)有的對(duì)象來提供新創(chuàng)建的對(duì)象的proto

參數(shù):

proto : 必須荡澎。表示新建對(duì)象的原型對(duì)象均践,即該參數(shù)會(huì)被賦值到目標(biāo)對(duì)象(即新對(duì)象,或說是最后返回的對(duì)象)的原型上摩幔。該參數(shù)可以是null彤委,對(duì)象, 函數(shù)的prototype屬性(創(chuàng)建空的對(duì)象時(shí)需傳null , 否則會(huì)拋出TypeError異常)或衡。

propertiesObject : 可選焦影。 添加到新創(chuàng)建對(duì)象的可枚舉屬性(即其自身的屬性,而不是原型鏈上的枚舉屬性)對(duì)象的屬性描述符以及相應(yīng)的屬性名稱薇宠。這些屬性對(duì)應(yīng)Object.defineProperties()的第二個(gè)參數(shù)偷办。

3 返回值:

在指定原型對(duì)象上添加新屬性后的對(duì)象。

案例說明:

1)創(chuàng)建對(duì)象的方式不同

new Object() 通過構(gòu)造函數(shù)來創(chuàng)建對(duì)象, 添加的屬性是在自身實(shí)例下澄港。

Object.create() es6創(chuàng)建對(duì)象的另一種方式椒涯,可以理解為繼承一個(gè)對(duì)象, 添加的屬性是在原型下。

// new Object() 方式創(chuàng)建

var a = {? rep : 'apple' }

var b = new Object(a)

console.log(b) // {rep: "apple"}

console.log(b.__proto__) // {}

console.log(b.rep) // {rep: "apple"}

// Object.create() 方式創(chuàng)建

var a = { rep: 'apple' }

var b = Object.create(a)

console.log(b)? // {}

console.log(b.__proto__) // {rep: "apple"}

console.log(b.rep) // {rep: "apple"}

Object.create()方法創(chuàng)建的對(duì)象時(shí)回梧,屬性是在原型下面的废岂,也可以直接訪問 b.rep // {rep: "apple"} ,

此時(shí)這個(gè)值不是吧b自身的,是它通過原型鏈proto來訪問到b的值狱意。

2)創(chuàng)建對(duì)象屬性的性質(zhì)不同

// 創(chuàng)建一個(gè)以另一個(gè)空對(duì)象為原型,且擁有一個(gè)屬性p的對(duì)象

o = Object.create({}, { p: { value: 42 } })

// 省略了的屬性特性默認(rèn)為false,所以屬性p是不可寫,不可枚舉,不可配置的:

o.p = 24

o.p

//42

o.q = 12

for (var prop in o) {

? console.log(prop)

}

//"q"

delete o.p

//false

Object.create() 用第二個(gè)參數(shù)來創(chuàng)建非空對(duì)象的屬性描述符默認(rèn)是為false的湖苞,而構(gòu)造函數(shù)或字面量方法創(chuàng)建的對(duì)象屬性的描述符默認(rèn)為true。

3)創(chuàng)建空對(duì)象時(shí)不同

當(dāng)用構(gòu)造函數(shù)或?qū)ο笞置媪糠椒▌?chuàng)建空對(duì)象時(shí)详囤,對(duì)象時(shí)有原型屬性的财骨,即有_proto_;

當(dāng)用Object.create()方法創(chuàng)建空對(duì)象時(shí)镐作,對(duì)象是沒有原型屬性的。


3. 怎樣判斷“值”屬于哪種數(shù)據(jù)類型隆箩?typeof 是否能正確判斷類型该贾?instanceof 呢?

首先typeof 能夠判斷基本數(shù)據(jù)類型捌臊,但是除了null杨蛋,typeof null 返回的是object

但是對(duì)于對(duì)象來說typeof不能準(zhǔn)確判斷類型,typeof 函數(shù)會(huì)返回function理澎,除此之外全部都是object逞力,不能準(zhǔn)確判斷類型

instanceof可以判斷復(fù)雜數(shù)據(jù)類型,基本數(shù)據(jù)類型不可以糠爬,instanceof是通過原型鏈來判斷的 寇荧,A instanceof B,在A的原型鏈中層層查找秩铆,是否有原型等于B.prototype砚亭,如果一直找到A的原型鏈的頂端(null,即Object.prototype._proto_)殴玛,仍然不等于B捅膘,那么返回false,否則返回true


4. instanceof 有什么作用滚粟??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的寻仗?

nstanceOf判斷一個(gè)對(duì)象是不是某個(gè)類型的實(shí)例

[1, 2, 3] instanceof Array; //true

可以看到[1, 2, 3]是類型Array的實(shí)例

[1, 2, 3] instanceof Object; //true


5.JavaScript 有哪些方法定義對(duì)象?

方式一:

通過對(duì)象字面量表示法(又稱為直接量凡壤、原始方式)署尤。

var obj = {name:"moyu"};

方式二:

通過new和構(gòu)造函數(shù)Object()、String()等亚侠。

var obj = new Object();

方式三:

自定義一個(gè)對(duì)象的構(gòu)造函數(shù)曹体,然后實(shí)例化對(duì)象。

function a(o){

this.name = "moyu"

}

var obj = new a();

方式四:

通過Object.create()

var o1 = Object.create({x:1, y:2}); ? ? ?// o1繼承了屬性x和y


6. 如下代碼中硝烂?new 一個(gè)函數(shù)本質(zhì)上做了什么箕别?

? ? function Modal(msg) {

? ? ? this.msg = msg

? ? }

? ? var modal = new Modal()

1.執(zhí)行 new Modal()

1.1創(chuàng)建一個(gè)空對(duì)象 {},假設(shè)名字是 tmpObj

1.2執(zhí)行 Modal 函數(shù)滞谢,執(zhí)行過程中對(duì) this 操作就是對(duì) tmpObj 進(jìn)行操作

1.3 函數(shù)執(zhí)行完后返回剛剛創(chuàng)建的 tmpObj

2.把 tmpObj 賦值給 modal (modal指向同一個(gè)對(duì)象)


8.2 使用原型

1. JS 原型是什么旦装?如何理解原型鏈偏瓤?

一叛买、什么是原型

原型是Javascript中的繼承的基礎(chǔ)爽柒,JavaScript的繼承就是基于原型的繼承。

1.1 函數(shù)的原型對(duì)象

在JavaScript中橄教,我們創(chuàng)建一個(gè)函數(shù)A(就是聲明一個(gè)函數(shù)), 那么瀏覽器就會(huì)在內(nèi)存中創(chuàng)建一個(gè)對(duì)象B清寇,而且每個(gè)函數(shù)都默認(rèn)會(huì)有一個(gè)屬性 prototype 指向了這個(gè)對(duì)象( 即:prototype的屬性的值是這個(gè)對(duì)象 )喘漏。這個(gè)對(duì)象B就是函數(shù)A的原型對(duì)象,簡(jiǎn)稱函數(shù)的原型颗管。這個(gè)原型對(duì)象B 默認(rèn)會(huì)有一個(gè)屬性 constructor 指向了這個(gè)函數(shù)A ( 意思就是說:constructor屬性的值是函數(shù)A )陷遮。

看下面的代碼:

<body>

? ? <script type="text/javascript">

? ? /*

? ? 聲明一個(gè)函數(shù)滓走,則這個(gè)函數(shù)默認(rèn)會(huì)有一個(gè)屬性叫 prototype 垦江。而且瀏覽器會(huì)自動(dòng)按照一定的規(guī)則

? ? 創(chuàng)建一個(gè)對(duì)象,這個(gè)對(duì)象就是這個(gè)函數(shù)的原型對(duì)象搅方,prototype屬性指向這個(gè)原型對(duì)象比吭。這個(gè)原型對(duì)象

? ? 有一個(gè)屬性叫constructor 執(zhí)行了這個(gè)函數(shù)

注意:原型對(duì)象默認(rèn)只有屬性:constructor。其他都是從Object繼承而來姨涡,暫且不用考慮衩藤。

*/

? ? function Person () {


? ? } ? ?

? ? </script>

</body>

下面的圖描述了聲明一個(gè)函數(shù)之后發(fā)生的事情:

1.2 使用構(gòu)造函數(shù)創(chuàng)建對(duì)象

當(dāng)把一個(gè)函數(shù)作為構(gòu)造函數(shù) (理論上任何函數(shù)都可以作為構(gòu)造函數(shù)) 使用new創(chuàng)建對(duì)象的時(shí)候,那么這個(gè)對(duì)象就會(huì)存在一個(gè)默認(rèn)的不可見的屬性涛漂,來指向了構(gòu)造函數(shù)的原型對(duì)象赏表。 這個(gè)不可見的屬性我們一般用 [[prototype]] 來表示,只是這個(gè)屬性沒有辦法直接訪問到匈仗。

看下面的代碼:

<body>

? ? <script type="text/javascript">

? ? function Person () {


? ? }

? ? ? ? /*

? ? ? ? 利用構(gòu)造函數(shù)創(chuàng)建一個(gè)對(duì)象瓢剿,則這個(gè)對(duì)象會(huì)自動(dòng)添加一個(gè)不可見的屬性 [[prototype]], 而且這個(gè)屬性

? ? ? ? 指向了構(gòu)造函數(shù)的原型對(duì)象。

? ? ? ? */

? ? ? var p1 = new Person();

? ? </script>

</body>

觀察下面的示意圖:

說明:

? ? 從上面的圖示中可以看到悠轩,創(chuàng)建p1對(duì)象雖然使用的是Person構(gòu)造函數(shù)间狂,但是對(duì)象創(chuàng)建出來之后,這個(gè)p1對(duì)象其實(shí)已經(jīng)與Person構(gòu)造函數(shù)沒有任何關(guān)系了火架,p1對(duì)象的[[ prototype ]]屬性指向的是Person構(gòu)造函數(shù)的原型對(duì)象鉴象。

? ? 如果使用new Person()創(chuàng)建多個(gè)對(duì)象,則多個(gè)對(duì)象都會(huì)同時(shí)指向Person構(gòu)造函數(shù)的原型對(duì)象何鸡。

? ? 我們可以手動(dòng)給這個(gè)原型對(duì)象添加屬性和方法纺弊,那么p1,p2,p3…這些對(duì)象就會(huì)共享這些在原型中添加的屬性和方法。

? ? 如果我們?cè)L問p1中的一個(gè)屬性name骡男,如果在p1對(duì)象中找到淆游,則直接返回。如果p1對(duì)象中沒有找到洞翩,則直接去p1對(duì)象的[[prototype]]屬性指向的原型對(duì)象中查找稽犁,如果查找到則返回。(如果原型中也沒有找到骚亿,則繼續(xù)向上找原型的原型—原型鏈已亥。 后面再講)。

? ? 如果通過p1對(duì)象添加了一個(gè)屬性name来屠,則p1對(duì)象來說就屏蔽了原型中的屬性name虑椎。 換句話說:在p1中就沒有辦法訪問到原型的屬性name了震鹉。

? ? 通過p1對(duì)象只能讀取原型中的屬性name的值,而不能修改原型中的屬性name的值捆姜。 p1.name = “李四”; 并不是修改了原型中的值传趾,而是在p1對(duì)象中給添加了一個(gè)屬性name。

? ? 看下面的代碼:

<body>

? ? <script type="text/javascript">

? ? function Person () {? ?

? ? }

? ? ? // 可以使用Person.prototype 直接訪問到原型對(duì)象

? ? //給Person函數(shù)的原型對(duì)象中添加一個(gè)屬性 name并且值是 "張三"

? ? Person.prototype.name = "張三";

? ? Person.prototype.age = 20;

? var p1 = new Person();

? /*

? 訪問p1對(duì)象的屬性name泥技,雖然在p1對(duì)象中我們并沒有明確的添加屬性name浆兰,但是

? p1的 [[prototype]] 屬性指向的原型中有name屬性,所以這個(gè)地方可以訪問到屬性name

? 就值珊豹。

? 注意:這個(gè)時(shí)候不能通過p1對(duì)象刪除name屬性簸呈,因?yàn)橹荒軇h除在p1中刪除的對(duì)象。

? */

? alert(p1.name);? // 張三

? var p2 = new Person();

? alert(p2.name);? // 張三? 都是從原型中找到的店茶,所以一樣蜕便。

? alert(p1.name === p2.name);? // true

? // 由于不能修改原型中的值,則這種方法就直接在p1中添加了一個(gè)新的屬性name贩幻,然后在p1中無法再訪問到

? //原型中的屬性轿腺。

? p1.name = "李四";

? alert("p1:" + p1.name);

? // 由于p2中沒有name屬性,則對(duì)p2來說仍然是訪問的原型中的屬性丛楚。

? alert("p2:" + p2.name);? // 張三?

? ? </script>

</body>

二族壳、與原型有關(guān)的幾個(gè)屬性和方法

2.1 prototype屬性

prototype 存在于構(gòu)造函數(shù)中 (其實(shí)任意函數(shù)中都有,只是不是構(gòu)造函數(shù)的時(shí)候prototype我們不關(guān)注而已) 鸯檬,他指向了這個(gè)構(gòu)造函數(shù)的原型對(duì)象决侈。

參考前面的示意圖。

2.2 constructor屬性

constructor屬性存在于原型對(duì)象中喧务,他指向了構(gòu)造函數(shù)

看下面的代碼:

<script type="text/javascript">

function Person () {

}

alert(Person.prototype.constructor === Person); // true

var p1 = new Person();

? //使用instanceof 操作符可以判斷一個(gè)對(duì)象的類型赖歌。?

? //typeof一般用來獲取簡(jiǎn)單類型和函數(shù)。而引用類型一般使用instanceof功茴,因?yàn)橐妙愋陀胻ypeof 總是返回object庐冯。

alert(p1 instanceof Person); // true

</script>

? ? 我們根據(jù)需要,可以Person.prototype 屬性指定新的對(duì)象坎穿,來作為Person的原型對(duì)象展父。

? ? 但是這個(gè)時(shí)候有個(gè)問題,新的對(duì)象的constructor屬性則不再指向Person構(gòu)造函數(shù)了玲昧。

看下面的代碼:

<script type="text/javascript">

function Person () {

}

//直接給Person的原型指定對(duì)象字面量栖茉。則這個(gè)對(duì)象的constructor屬性不再指向Person函數(shù)

Person.prototype = {

name:"志玲",

age:20

};

var p1 = new Person();

alert(p1.name);? // 志玲

alert(p1 instanceof Person); // true

alert(Person.prototype.constructor === Person); //false

? //如果constructor對(duì)你很重要,你應(yīng)該在Person.prototype中添加一行這樣的代碼:

? /*

? Person.prototype = {

? ? ? constructor : Person //讓constructor重新指向Person函數(shù)

? }

? */

</script>

2.3 __proto__ 屬性(注意:左右各是2個(gè)下劃線)

用構(gòu)造方法創(chuàng)建一個(gè)新的對(duì)象之后孵延,這個(gè)對(duì)象中默認(rèn)會(huì)有一個(gè)不可訪問的屬性 [[prototype]] , 這個(gè)屬性就指向了構(gòu)造方法的原型對(duì)象吕漂。

但是在個(gè)別瀏覽器中,也提供了對(duì)這個(gè)屬性[[prototype]]的訪問(chrome瀏覽器和火狐瀏覽器尘应。ie瀏覽器不支持)惶凝。訪問方式:p1.__proto__

但是開發(fā)者盡量不要用這種方式去訪問吼虎,因?yàn)椴僮鞑簧鲿?huì)改變這個(gè)對(duì)象的繼承原型鏈。

<script type="text/javascript">

function Person () {

}

//直接給Person的原型指定對(duì)象字面量苍鲜。則這個(gè)對(duì)象的constructor屬性不再指向Person函數(shù)

Person.prototype = {

constructor : Person,

name:"志玲",

age:20

};

var p1 = new Person();

alert(p1.__proto__ === Person.prototype); //true

</script>

2.4 hasOwnProperty() 方法

大家知道思灰,我們用去訪問一個(gè)對(duì)象的屬性的時(shí)候,這個(gè)屬性既有可能來自對(duì)象本身混滔,也有可能來自這個(gè)對(duì)象的[[prototype]]屬性指向的原型洒疚。

那么如何判斷這個(gè)對(duì)象的來源呢?

hasOwnProperty方法遍坟,可以判斷一個(gè)屬性是否來自對(duì)象本身拳亿。

<script type="text/javascript">

function Person () {

}

Person.prototype.name = "志玲";

var p1 = new Person();

p1.sex = "女";

? //sex屬性是直接在p1屬性中添加,所以是true

alert("sex屬性是對(duì)象本身的:" + p1.hasOwnProperty("sex"));

? // name屬性是在原型中添加的愿伴,所以是false

alert("name屬性是對(duì)象本身的:" + p1.hasOwnProperty("name"));

? //? age 屬性不存在,所以也是false

alert("age屬性是存在于對(duì)象本身:" + p1.hasOwnProperty("age"));

</script>

? ? 所以电湘,通過hasOwnProperty這個(gè)方法可以判斷一個(gè)對(duì)象是否在對(duì)象本身添加的隔节,但是不能判斷是否存在于原型中,因?yàn)橛锌赡苓@個(gè)屬性不存在寂呛。

? ? 也即是說怎诫,在原型中的屬性和不存在的屬性都會(huì)返回fasle。

? ? 如何判斷一個(gè)屬性是否存在于原型中呢贷痪?

2.5 in 操作符

in操作符用來判斷一個(gè)屬性是否存在于這個(gè)對(duì)象中幻妓。但是在查找這個(gè)屬性時(shí)候,現(xiàn)在對(duì)象本身中找劫拢,如果對(duì)象找不到再去原型中找肉津。換句話說,只要對(duì)象和原型中有一個(gè)地方存在這個(gè)屬性舱沧,就返回true

<script type="text/javascript">

function Person () {

}

Person.prototype.name = "志玲";

var p1 = new Person();

p1.sex = "女";

alert("sex" in p1); // 對(duì)象本身添加的妹沙,所以true

alert("name" in p1); //原型中存在,所以true

alert("age" in p1); //對(duì)象和原型中都不存在熟吏,所以false

</script>

回到前面的問題距糖,如果判斷一個(gè)屬性是否存在于原型中:

如果一個(gè)屬性存在,但是沒有在對(duì)象本身中牵寺,則一定存在于原型中悍引。

<script type="text/javascript">

function Person () {

}

Person.prototype.name = "志玲";

var p1 = new Person();

p1.sex = "女";

//定義一個(gè)函數(shù)去判斷原型所在的位置

function propertyLocation(obj, prop){

if(!(prop in obj)){

alert(prop + "屬性不存在");

}else if(obj.hasOwnProperty(prop)){

alert(prop + "屬性存在于對(duì)象中");

}else {

alert(prop + "對(duì)象存在于原型中");

}

}

propertyLocation(p1, "age");

propertyLocation(p1, "name");

propertyLocation(p1, "sex");

</script

三、組合原型模型和構(gòu)造函數(shù)模型創(chuàng)建對(duì)象

3.1 原型模型創(chuàng)建對(duì)象的缺陷

原型中的所有的屬性都是共享的帽氓。也就是說趣斤,用同一個(gè)構(gòu)造函數(shù)創(chuàng)建的對(duì)象去訪問原型中的屬性的時(shí)候,大家都是訪問的同一個(gè)對(duì)象杏节,如果一個(gè)對(duì)象對(duì)原型的屬性進(jìn)行了修改唬渗,則會(huì)反映到所有的對(duì)象上面典阵。

但是在實(shí)際使用中,每個(gè)對(duì)象的屬性一般是不同的镊逝。張三的姓名是張三壮啊,李四的姓名是李四。

**但是撑蒜,這個(gè)共享特性對(duì) 方法(屬性值是函數(shù)的屬性)又是非常合適的歹啼。**所有的對(duì)象共享方法是最佳狀態(tài)。這種特性在c#和Java中是天生存在的座菠。

3.2 構(gòu)造函數(shù)模型創(chuàng)建對(duì)象的缺陷

在構(gòu)造函數(shù)中添加的屬性和方法狸眼,每個(gè)對(duì)象都有自己獨(dú)有的一份,大家不會(huì)共享浴滴。這個(gè)特性對(duì)屬性比較合適拓萌,但是對(duì)方法又不太合適。因?yàn)閷?duì)所有對(duì)象來說升略,他們的方法應(yīng)該是一份就夠了微王,沒有必要每人一份,造成內(nèi)存的浪費(fèi)和性能的低下品嚣。

<script type="text/javascript">

function Person() {

? ? this.name = "李四";

? ? this.age = 20;

? ? this.eat = function() {

? ? ? ? alert("吃完東西");

? ? }

}

var p1 = new Person();

var p2 = new Person();

//每個(gè)對(duì)象都會(huì)有不同的方法

alert(p1.eat === p2.eat); //fasle

</script>

可以使用下面的方法解決:

<script type="text/javascript">

function Person() {

? ? this.name = "李四";

? ? this.age = 20;

? ? this.eat = eat;

}

? function eat() {

? ? alert("吃完東西");

? ? }

var p1 = new Person();

var p2 = new Person();

//因?yàn)閑at屬性都是賦值的同一個(gè)函數(shù)炕倘,所以是true

alert(p1.eat === p2.eat); //true

</script>

? ? 但是上面的這種解決方法具有致命的缺陷:封裝性太差。使用面向?qū)ο蠛渤牛康闹痪褪欠庋b代碼罩旋,這個(gè)時(shí)候?yàn)榱诵阅苡忠汛a抽出對(duì)象之外,這是反人類的設(shè)計(jì)眶诈。

3.3 使用組合模式解決上述兩種缺陷

原型模式適合封裝方法涨醋,構(gòu)造函數(shù)模式適合封裝屬性,綜合兩種模式的優(yōu)點(diǎn)就有了組合模式册养。

<script type="text/javascript">

//在構(gòu)造方法內(nèi)部封裝屬性

function Person(name, age) {

? ? this.name = name;

? ? this.age = age;

}

//在原型對(duì)象內(nèi)封裝方法

Person.prototype.eat = function (food) {

alert(this.name + "愛吃" + food);

}

Person.prototype.play = function (playName) {

alert(this.name + "愛玩" + playName);

}

var p1 = new Person("李四", 20);

var p2 = new Person("張三", 30);

p1.eat("蘋果");

p2.eat("香蕉");

p1.play("志玲");

p2.play("鳳姐");

</script>

四东帅、動(dòng)態(tài)原型模式創(chuàng)建對(duì)象

前面講到的組合模式,也并非完美無缺球拦,有一點(diǎn)也是感覺不是很完美靠闭。把構(gòu)造方法和原型分開寫,總讓人感覺不舒服坎炼,應(yīng)該想辦法把構(gòu)造方法和原型封裝在一起愧膀,所以就有了動(dòng)態(tài)原型模式。

動(dòng)態(tài)原型模式把所有的屬性和方法都封裝在構(gòu)造方法中谣光,而僅僅在需要的時(shí)候才去在構(gòu)造方法中初始化原型檩淋,又保持了同時(shí)使用構(gòu)造函數(shù)和原型的優(yōu)點(diǎn)。

? ? 看下面的代碼:

<script type="text/javascript">

//構(gòu)造方法內(nèi)部封裝屬性

function Person(name, age) {

//每個(gè)對(duì)象都添加自己的屬性

? ? this.name = name;

? ? this.age = age;

? ? /*

? ? 判斷this.eat這個(gè)屬性是不是function,如果不是function則證明是第一次創(chuàng)建對(duì)象蟀悦,

? ? 則把這個(gè)funcion添加到原型中媚朦。

? ? 如果是function,則代表原型中已經(jīng)有了這個(gè)方法日戈,則不需要再添加询张。

? ? perfect!完美解決了性能和代碼的封裝問題浙炼。

? ? */

? ? if(typeof this.eat !== "function"){

? ? Person.prototype.eat = function () {

? ? alert(this.name + " 在吃");

? ? }

? ? }

}

var p1 = new Person("志玲", 40);

p1.eat();

</script>

? ? 說明:

? ? 組合模式和動(dòng)態(tài)原型模式是JavaScript中使用比較多的兩種創(chuàng)建對(duì)象的方式份氧。

? ? 建議以后使用動(dòng)態(tài)原型模式。他解決了組合模式的封裝不徹底的缺點(diǎn)弯屈。

原文鏈接:https://blog.csdn.net/u012468376/java/article/details/53121081

五蜗帜、原型鏈

每個(gè)實(shí)例對(duì)象( object )都有一個(gè)私有屬性(稱之為 __proto__ )指向它的構(gòu)造函數(shù)的原型對(duì)象(prototype )。該原型對(duì)象也有一個(gè)自己的原型對(duì)象( __proto__ ) 资厉,層層向上直到一個(gè)對(duì)象的原型對(duì)象為null厅缺。根據(jù)定義,null沒有原型酌住,并作為這個(gè)原型鏈中的最后一個(gè)環(huán)節(jié)店归。

2. JS 如何實(shí)現(xiàn)繼承?

一酪我、原型鏈實(shí)現(xiàn)繼承

原型鏈實(shí)現(xiàn)繼承的思想:利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。

原型鏈的基本概念:? 當(dāng)一個(gè)原型對(duì)象等于另一個(gè)類型的實(shí)例且叁,此時(shí)的原型對(duì)象將包含一個(gè)指向另一個(gè)指向另一個(gè)原型的指針都哭。同時(shí),另一個(gè)原型中也包含著一個(gè)指向另一個(gè)構(gòu)造函數(shù)的指針逞带。如果另一個(gè)原型是另一個(gè)類型的實(shí)例欺矫,此時(shí)實(shí)例和原型就構(gòu)成了原型鏈

function SuperType(){

? ? ? this.property=true;

}

SuperType.prototype.getSuperValue=function(){

? ? ? returnthis.property;

}

function SubType(){

? ? ? this.subproperty=false;

}//通過創(chuàng)建SuperType的實(shí)例繼承了SuperTypeSubType.prototype=new SuperType();SubType.prototype.getSubValue=function(){

? ? ? returnthis.subproperty;

}

var instance=new SubType();

alert(instance.getSuperValue());? //true

對(duì)于代碼的解釋:

首先定義了兩個(gè)類型SuperType和SubType。此時(shí)SubType通過創(chuàng)建SuperType的實(shí)例(new SuperType())展氓,并將該實(shí)例(new?SuperType())賦給了SubType的原型SubType.prototype的方式? ?繼承了 SuperType穆趴。

此時(shí)存在于SuperType中實(shí)例中的所有屬性和方法,也存在于SubType.prototype中遇汞。此時(shí)未妹,實(shí)例、原型和構(gòu)造函數(shù)之間的關(guān)系如下圖所示空入。

SubType的實(shí)例instance指向SubType的原型SubType.prototype络它,SubType.prototype又指向SuperType的原型。

注意:getSuperValue()方法仍然還在SuperType.prototype中歪赢,但property則位于SubType.prototype中化戳。這是因?yàn)閜roperty是一個(gè)實(shí)例屬性,而getSuperValue()則是一個(gè)原型方法埋凯。

原型鏈存在的問題:

1)包含引用類型值的原型屬性會(huì)被所有實(shí)例共享点楼,這會(huì)導(dǎo)致對(duì)一個(gè)實(shí)例的修改會(huì)影響另一個(gè)實(shí)例扫尖。在通過原型來實(shí)現(xiàn)繼承時(shí),原型實(shí)際上會(huì)變成另一個(gè)類型的實(shí)例掠廓。原先的實(shí)例屬性就變成了現(xiàn)在的原型屬性

(2)在創(chuàng)建子類型的實(shí)例時(shí)换怖,不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)

二、借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承

借用構(gòu)造函數(shù)基本思想却盘,即在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類型構(gòu)造函數(shù)狰域。函數(shù)只不過是在特定環(huán)境中執(zhí)行代碼的對(duì)象,因此通過使用apply()和call()方法可以在新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)黄橘。

function SuperType(){

? ? ? this.colors=["red", "blue", "green"];

}function SubType(){

? ? ? //繼承SuperType? SuperType.call(this);}varinstance1=new SubType();

instance1.colors.push("black");

alert(instance1.colors);? //red,bllue,green,blackvarinstance2=new SubType();

alert(instance2.colors);? //red,blue,green

代碼的解釋:

SuperType.call(this);“借調(diào)”了超類型的構(gòu)造函數(shù)兆览。通過使用call()方法(或者apply()方法),在新創(chuàng)建的SubType實(shí)例的環(huán)境下調(diào)用了SuperType構(gòu)造函數(shù)塞关。這樣一來就會(huì)在新的SubType對(duì)象上執(zhí)行SuperType()函數(shù)中定義的所有對(duì)象初始化代碼抬探。結(jié)果,SubType的每個(gè)實(shí)例都會(huì)有自己的colors屬性副本

借用構(gòu)造函數(shù)的優(yōu)勢(shì):可以在子類型構(gòu)造函數(shù)中向超類型構(gòu)造函數(shù)傳遞參數(shù)


function SuperType(name){

? ? ? this.name=name;

}function SubType(){

? ? ? //繼承了SuperType,同時(shí)還傳遞了參數(shù)SuperType.call(this,"mary");//this(SubType的實(shí)例)調(diào)用SuperType構(gòu)造函數(shù)

? ? ? //實(shí)例屬性this.age=22;

}varinstance=new SubType();

alert(instance.name);? //maryalert(instance.age);//29


借用構(gòu)造函數(shù)的問題:

1)無法避免構(gòu)造函數(shù)模式存在的問題帆赢,方法都在構(gòu)造函數(shù)中定義小压,因此無法復(fù)用函數(shù)。

2)在超類型的原型中定義的方法椰于,對(duì)子類型而言是不可見的怠益。因此這種技術(shù)很少單獨(dú)使用。

三瘾婿、組合繼承

組合繼承:指的是將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一起蜻牢。思路是使用原型鏈實(shí)現(xiàn)對(duì)原型方法的繼承,而通過借用構(gòu)造函數(shù)來實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承偏陪。這樣抢呆,既通過在原型上定義方法實(shí)現(xiàn)了函數(shù)的復(fù)用,又能夠保證每個(gè)實(shí)例都有它自己的屬性笛谦。

function SuperType(name){

? ? ? this.name=name;

? ? ? this.colors=["red", "blue", "green"];

}

SuperType.prototype.sayName=function(){

? ? ? alert(this.name);

};function SubType(name, age){

? ? ? //繼承屬性? ? 使用借用構(gòu)造函數(shù)實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承? ? SuperType.call(this,name);

? ? ? this.age=age;

}//繼承方法? ? 使用原型鏈實(shí)現(xiàn)SubType.prototype=new SuperType();SubType.prototype.constructor=SubType;

subType.prototype.sayAge=function(){

? ? ? alert(this.age);

};varinstance1=newSubType("mary", 22);

instance1.colors.push("black");

alert(instance1.colors);? //red,blue,green,blackinstance1.sayName();//maryinstance1.sayAge();//22varinstance2=newSubType("greg", 25);

alert(instance2.colors);? //red,blue,greeninstance2.sayName();//greginstance2.sayAge();//25

代碼解釋:

? SuperType構(gòu)造函數(shù)定義了兩個(gè)屬性:name和colors抱虐。SuperType的原型定義了一個(gè)方法sayName()。

? SubType構(gòu)造函數(shù)在調(diào)用SuperType構(gòu)造函數(shù)時(shí)傳入了name參數(shù)饥脑。并定義了自己的屬性age恳邀。

然后,將SuperType實(shí)例賦值給SubType的原型好啰,然后又在新原型上定義了sayAge方法轩娶。

此時(shí)可以讓兩個(gè)不同的SubType實(shí)例分別擁有自己的屬性,又可以使用相同的方法

組合繼承的優(yōu)勢(shì):

避免了原型鏈和借用構(gòu)造函數(shù)的缺點(diǎn)框往,融合了他們的優(yōu)點(diǎn)鳄抒,是JavaScript中最常用的繼承模式。instanceof和isprototypeOf()也能夠用于識(shí)別基于組合繼承創(chuàng)建的對(duì)象

四、原型式繼承

五许溅、寄生式繼承

六瓤鼻、寄生組合式繼承

3. 實(shí)現(xiàn)一個(gè)函數(shù) clone 可以對(duì) JavaScript 中的五種主要數(shù)據(jù)類型(Number、string贤重、Object茬祷、Array、

? ? Boolean)進(jìn)行復(fù)制并蝗?

function clone(obj) {

? var o;

? switch (typeof obj) {

? ? case "undefined":

? ? ? ? break;

? ? case "string":

? ? ? ? o = obj + "";

? ? ? ? break;

? ? case "number":

? ? ? ? o = obj - 0;

? ? ? ? break;

? ? case "boolean":

? ? ? ? o = obj;

? ? ? ? break;

? ? case "object": // object 分為兩種情況 對(duì)象(Object)或數(shù)組(Array)

? ? if (obj === null) {

? ? ? ? o = null;

? ? } else {

? ? ? if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {

? ? ? ? o = [];

? ? ? ? for (var i = 0; i < obj.length; i++) {

? ? ? ? ? ? o.push(clone(obj[i]));

? ? ? ? }

? ? ? } else {

? ? ? ? o = {};

? ? ? ? for (var k in obj) {

? ? ? ? ? ? o[k] = clone(obj[k]);

? ? ? ? }

? ? ? }

? ? }

? ? break;

? default:

? ? o = obj;

? ? break;

? }

? return o;

}


4. 對(duì) String 做擴(kuò)展祭犯,實(shí)現(xiàn)如下方式獲取字符串中頻率最高的字符:

var str = 'ahbbccdeddddfg';

//補(bǔ)充方法

String.prototype.getMostOften = function(){
? var obj = {}
? for(var i = 0; i<str.length; i++){
??? var letter = str.charAt(i)
??? if(!obj[letter]){
????? obj[letter] = 1
??? }else{
????? obj[letter]++
??? }
? }
? console.log(obj)
? var maxIdx = 0
? var maxLetter = ''
? for(var key in obj){
??? if(maxIdx < obj[key]){
????? maxIdx = obj[key]
????? maxLetter = key
??? }
? }
? return maxLetter
}

//

var ch = str.getMostOften()
console.log(ch) // d,因?yàn)?d 出現(xiàn)了 5 次


5. 有如下代碼滚停,代碼中并未添加 toString 方法沃粗,這個(gè)方法是哪里來的?畫出原型鏈圖進(jìn)行解釋:

? ? function People() {

? ? }

? ? var p = new People()

? ? p.toString()

分析如下:

記當(dāng)前對(duì)象為p键畴,查找p屬性最盅、方法

沒有找到,通過p的proto屬性起惕,找到其類型People的prototype屬性(記為prop)繼續(xù)查找

沒有找到涡贱,把prop記為obj做遞歸重復(fù)步驟一,通過類似方法找到prop的類型Object的 prototype進(jìn)行查找惹想,直至找到toString方法


6. 有如下代碼问词,解釋 Person、 prototype嘀粱、__proto__戏售、p、constructor 之間的關(guān)聯(lián):

? ? function Person(name) {

? ? ? this.name = name;

? ? }

? ? Person.prototype.sayName = function() {

? ? ? console.log("My name is :" + this.name);

? ? }

? ? var p = new Person("Oli")

? ? p.sayName();

分析:

1.我們通過函數(shù)定義了類Person草穆,類(函數(shù))Person自動(dòng)獲得屬性prototype

2.Person是一個(gè)構(gòu)造函數(shù),構(gòu)造函數(shù)構(gòu)造出實(shí)例 p搓译,

3.p是構(gòu)造函數(shù)Person的一個(gè)實(shí)例悲柱,p的 proto 指向了Person的prototype屬性,

4.prototype是構(gòu)造函數(shù)內(nèi)部的原型對(duì)象些己,所以擁有contructor和proto屬性豌鸡,其中contructor屬性指向構(gòu)造函數(shù)Person,proto指向該對(duì)象的原型.


7. 下面兩種寫法有什么區(qū)別段标?

? ? // 方法一:

? ? function People(name, sex) {

? ? ? this.name = name;

? ? ? this.sex = sex;

? ? ? this.printName = function() {

? ? ? ? console.log(this.name);

? ? ? }

? ? }

? ? var p1 = new People("Oli", 2)

? ? // 方法二:

? ? function Person(name, sex) {

? ? ? this.name = name;

? ? ? this.sex = sex;

? ? }

? ? Person.prototype.printName = function() {

? ? ? console.log(this.name);

? ? }

? ? var p1 = new Person("Aman", 2);

方法一是直接將方法放在自己的私有空間內(nèi)涯冠,沒有放在原型鏈上,并沒有起到公共代碼的作用

方法二通過將方法放在原型鏈上逼庞,起到了公共代碼的作用蛇更,節(jié)省了代碼量,提升了性能。


8. 補(bǔ)全代碼派任,實(shí)現(xiàn)繼承:

? ? function Person(name, sex){

? ? ? // 補(bǔ)全

????? this.name=name; // todo ...

????? this.sex=sex

? ? };

? ? Person.prototype.getName = function() {

? ? ? // 補(bǔ)全?????

??????? console.log(this.name)// todo ...

? ? };

? ? function Male(name, sex, age) {

? ? ? // 補(bǔ)全

????? Person.call(this,name,sex)
????? this.age=age //todo ...

? ? };

? ? ? // 補(bǔ)全

????? Male.prototype=Object.create(Person.prototype);//todo ...

????? Male.prototype.constructor=Male

? ? Male.prototype.getAge = function() {

? ? ? // 補(bǔ)全

????? onsole.log(this.age)//todo ...

? ? };

? ? var catcher = new Male("Oli", "男", 2);

? ? catcher.getName();


9. 如下代碼中 call 的作用是什么砸逊?

? ? function Person(name, sex) {

? ? ? this.name = name;

? ? ? this.sex = sex;

? ? }

? ? function Male(name, sex, age) {

? ? ? Person.call(this, name, sex); // 這里的 call 有什么作用?

? ? ? this.age = age;

? ? }

call調(diào)用了Person構(gòu)造函數(shù)掌逛,將Person里面的this替換成指向Male構(gòu)造函數(shù)的對(duì)象

10.判斷字符串是否同構(gòu):如果 *__s __*中的字符可以被替換得到?*t *师逸,那么這兩個(gè)字符串是同構(gòu)的。所有出現(xiàn)的字符都必須用另一個(gè)字符替換豆混,同時(shí)保留字符的順序篓像。兩個(gè)字符不能映射到同一個(gè)字符上,但字符可以映射自己本身皿伺。

比如輸入: s = "egg", t = "add"员辩,輸出: true

輸入: s = "foo", t = "bar"輸出: false

var isIsomorphic = function(s, t) {

? ? let i = 0

? ? while (i < s.length) {

? ? ? if (s.indexOf(s[i]) != t.indexOf(t[i])){

? ? ? ? return false

? ? ? }

? ? ? i++

? ? }

? ? return true

};

console.log(isIsomorphic('foo','bar'));

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市心傀,隨后出現(xiàn)的幾起案子屈暗,更是在濱河造成了極大的恐慌,老刑警劉巖脂男,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件养叛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡宰翅,警方通過查閱死者的電腦和手機(jī)弃甥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汁讼,“玉大人淆攻,你說我怎么就攤上這事『偌埽” “怎么了瓶珊?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)耸彪。 經(jīng)常有香客問我伞芹,道長(zhǎng),這世上最難降的妖魔是什么蝉娜? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任唱较,我火速辦了婚禮,結(jié)果婚禮上召川,老公的妹妹穿的比我還像新娘南缓。我一直安慰自己,他們只是感情好荧呐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布汉形。 她就那樣靜靜地躺著纸镊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪获雕。 梳的紋絲不亂的頭發(fā)上薄腻,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音届案,去河邊找鬼庵楷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛楣颠,可吹牛的內(nèi)容都是我干的尽纽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼童漩,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼弄贿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起矫膨,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤差凹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后侧馅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體危尿,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年馁痴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谊娇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罗晕,死狀恐怖济欢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情小渊,我是刑警寧澤法褥,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站酬屉,受9級(jí)特大地震影響挖胃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梆惯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一劳较、第九天 我趴在偏房一處隱蔽的房頂上張望掺喻。 院中可真熱鬧介衔,春花似錦吟策、人聲如沸撞羽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽附较。三九已至,卻和暖如春锨络,著一層夾襖步出監(jiān)牢的瞬間赌躺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工羡儿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留礼患,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓掠归,卻偏偏與公主長(zhǎng)得像缅叠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子虏冻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345