這篇文章主要介紹“分析web前端中的JS”,在日常操作中,相信很多人在分析web前端中的JS問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”分析web前端中的JS”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括珠暉網(wǎng)站建設(shè)、珠暉網(wǎng)站制作、珠暉網(wǎng)頁(yè)制作以及珠暉網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,珠暉網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到珠暉省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!
當(dāng)執(zhí)行JS代碼時(shí),會(huì)生成執(zhí)行環(huán)境,只要代碼不是寫(xiě)在函數(shù)中的,就是在堆棧執(zhí)行環(huán)境中,函數(shù)中的代碼會(huì)產(chǎn)生函數(shù)執(zhí)行環(huán)境,僅此兩種執(zhí)行環(huán)境。
b() // call b
console.log(a) // undefined
var a = 'Hello world'
function b() {
console.log('call b')
}想必高于上述的輸出大家肯定都已經(jīng)明白了,這是因?yàn)楹瘮?shù)和變量提升的原因。通常提升的解釋是說(shuō)將聲明的代碼移動(dòng)到了頂部,這其實(shí)沒(méi)有什么錯(cuò)誤,便于大家理解。應(yīng)該是:在生成執(zhí)行環(huán)境時(shí),會(huì)有兩個(gè)階段。第一個(gè)階段是創(chuàng)建的階段,JS解釋器會(huì)尋找需要提升的變量和函數(shù),并且給他們提前在內(nèi)存中開(kāi)辟好空間,函數(shù)的話(huà)會(huì)將整個(gè)函數(shù)存入內(nèi)存中,變量只聲明和賦值undefined,所以在第二個(gè)階段,也就是代碼執(zhí)行階段,我們可以直接提前使用
在提升的過(guò)程中,相同的函數(shù)會(huì)覆蓋上一個(gè)函數(shù),并且函數(shù)優(yōu)先于變量提升
b() // call b second
function b() {
console.log('call b fist')
}
function b() {
console.log('call b second')
}
var b = 'Hello world'var會(huì)產(chǎn)生很多錯(cuò)誤,所以在ES6中約會(huì)了let。let不能在聲明前使用,但是這不是常說(shuō)的let不會(huì)提升,提升let了,在第一階段內(nèi)存也已經(jīng)為他開(kāi)辟好了空間,但是因?yàn)檫@個(gè)聲明的特性導(dǎo)致了并不能在聲明前使用
call和apply都是為了解決改變this的指向。作用都是相同的,只是傳參的方式不同。
除了第一個(gè)參數(shù)外,call可以接收一個(gè)參數(shù)列表,apply只接受一個(gè)參數(shù)列表
let a = {
value: 1
}
function getValue(name, age) {
console.log(name)
console.log(age)
console.log(this.value)
}
getValue.call(a, 'yck', '24')
getValue.apply(a, ['yck', '24'])bind和其他兩個(gè)方法作用也是一致的,只是該方法會(huì)返回一個(gè)函數(shù)。并且我們可以通過(guò)
bind實(shí)現(xiàn)柯里化
對(duì)于實(shí)現(xiàn)以下幾個(gè)函數(shù),可以從幾個(gè)方面思考
不預(yù)定第一個(gè)參數(shù),那么預(yù)設(shè)為 window
改變this思路指向,讓新的對(duì)象可以執(zhí)行該函數(shù)。那么思路是否可以變成給新的對(duì)象添加一個(gè)函數(shù),然后在執(zhí)行完以后刪除?
Function.prototype.myBind = function (context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
var _this = this
var args = [...arguments].slice(1)
// 返回一個(gè)函數(shù)
return function F() {
// 因?yàn)榉祷亓艘粋€(gè)函數(shù),我們可以 new F(),所以需要判斷
if (this instanceof F) {
return new _this(...args, ...arguments)
}
return _this.apply(context, args.concat(...arguments))
}
}Function.prototype.myCall = function (context) {
var context = context || window
// 給 context 添加一個(gè)屬性
// getValue.call(a, 'yck', '24') => a.fn = getValue
context.fn = this
// 將 context 后面的參數(shù)取出來(lái)
var args = [...arguments].slice(1)
// getValue.call(a, 'yck', '24') => a.fn('yck', '24')
var result = context.fn(...args)
// 刪除 fn
delete context.fn
return result
}Function.prototype.myApply = function (context) {
var context = context || window
context.fn = this
var result
// 需要判斷是否存儲(chǔ)第二個(gè)參數(shù)
// 如果存在,就將第二個(gè)參數(shù)展開(kāi)
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}每個(gè)函數(shù)都有prototype屬性,除了Function.prototype.bind(),該屬性指向原型。
每個(gè)對(duì)象都有__proto__屬性,指向了創(chuàng)建該對(duì)象的構(gòu)造函數(shù)的原型。其實(shí)這個(gè)屬性指向了[[prototype]],但是[[prototype]]是內(nèi)部屬性,我們并不能訪問(wèn)到,所以使用_proto_來(lái)訪問(wèn)。
對(duì)象可以通過(guò)__proto__來(lái)尋找不屬于該對(duì)象的屬性,__proto__將對(duì)象連接起來(lái)組成了原型鏈。
可以通過(guò)Object.prototype.toString.call(xx)。這樣我們就可以獲得類(lèi)似[object Type]的字符串。
instanceof 可以正確的判斷對(duì)象的類(lèi)型,因?yàn)閮?nèi)部機(jī)制是通過(guò)判斷對(duì)象的原型鏈中是不是能找到類(lèi)型的 prototype
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()())函數(shù)箭頭的英文其實(shí)沒(méi)有this的,函數(shù)這個(gè)中的this只取決于他外面的第一個(gè)不是箭頭函數(shù)的函數(shù)的this。在這個(gè)例子中,調(diào)用因?yàn)閍符合前面代碼中的第一個(gè)情況,所以this的英文window。并且this一旦綁定了一部分,就不會(huì)被任何代碼改變
function foo() {
console.log(this.a)
}
var a = 1
foo()
var obj = {
a: 2,
foo: foo
}
obj.foo()
// 以上兩者情況 `this` 只依賴(lài)于調(diào)用函數(shù)前的對(duì)象,優(yōu)先級(jí)是第二個(gè)情況大于第一個(gè)情況
// 以下情況是優(yōu)先級(jí)最高的,`this` 只會(huì)綁定在 `c` 上,不會(huì)被任何方式修改 `this` 指向
var c = new foo()
c.a = 3
console.log(c.a)
// 還有種就是利用 call,apply,bind 改變 this,這個(gè)優(yōu)先級(jí)僅次于 new
async和await在于直接使用而言Promise,優(yōu)勢(shì)在于處理then的調(diào)用鏈,能夠更清晰準(zhǔn)確的寫(xiě)出代碼。一致在于重復(fù)await可能會(huì)導(dǎo)致性能問(wèn)題,因?yàn)閍wait會(huì)分離代碼,也許之后的編碼并不依賴(lài)于前者,但仍然需要等待前者完成,導(dǎo)致代碼丟失了并發(fā)性
下面來(lái)看一個(gè)使用await的代碼。
var a = 0
var b = async () => {
a = a + await 10
console.log('2', a) // -> '2' 10
a = (await 10) + a
console.log('3', a) // -> '3' 20
}
b()
a++
console.log('1', a) // -> '1' 1首先函數(shù)b先執(zhí)行,在執(zhí)行到await 10之前變量a還是0,因?yàn)樵赼wait內(nèi)部實(shí)現(xiàn)了generators,generators會(huì)保留多個(gè)中東西,所以這時(shí)候a = 0被保存了下來(lái)
因?yàn)閍wait是異步操作,遇到await就會(huì)立即返回一個(gè)pending狀態(tài)的Promise對(duì)象,暫時(shí)返回執(zhí)行代碼的控制權(quán),導(dǎo)致函數(shù)外部的代碼可以繼續(xù)執(zhí)行,所以會(huì)先執(zhí)行console.log(‘1’, a)
這時(shí)候同步代碼執(zhí)行完畢,開(kāi)始執(zhí)行異步代碼,將保存下來(lái)的值拿出來(lái)使用,這時(shí)候 a = 10
然后后面就是常規(guī)執(zhí)行代碼了
Generator是ES6中新增的語(yǔ)法,和Promise一樣,都可以用來(lái)初始化編程
// 使用 * 表示這是一個(gè) Generator 函數(shù)
// 內(nèi)部可以通過(guò) yield 暫停代碼
// 通過(guò)調(diào)用 next 恢復(fù)執(zhí)行
function* test() {
let a = 1 + 2;
yield 2;
yield 3;
}
let b = test();
console.log(b.next()); // > { value: 2, done: false }
console.log(b.next()); // > { value: 3, done: false }
console.log(b.next()); // > { value: undefined, done: true }從以上代碼可以發(fā)現(xiàn),加上*的函數(shù)執(zhí)行后擁有了next函數(shù),然后函數(shù)執(zhí)行后返回了一個(gè)對(duì)象。每次調(diào)用next函數(shù)可以繼續(xù)執(zhí)行被暫停的代碼。以下是Generator函數(shù)的簡(jiǎn)單實(shí)現(xiàn)
// cb 也就是編譯過(guò)的 test 函數(shù)
function generator(cb) {
return (function() {
var object = {
next: 0,
stop: function() {}
};
return {
next: function() {
var ret = cb(object);
if (ret === undefined) return { value: undefined, done: true };
return {
value: ret,
done: false
};
}
};
})();
}
// 如果你使用 babel 編譯后可以發(fā)現(xiàn) test 函數(shù)變成了這樣
function test() {
var a;
return generator(function(_context) {
while (1) {
switch ((_context.prev = _context.next)) {
// 可以發(fā)現(xiàn)通過(guò) yield 將代碼分割成幾塊
// 每次執(zhí)行 next 函數(shù)就執(zhí)行一塊代碼
// 并且表明下次需要執(zhí)行哪塊代碼
case 0:
a = 1 + 2;
_context.next = 4;
return 2;
case 4:
_context.next = 6;
return 3;
// 執(zhí)行完畢
case 6:
case "end":
return _context.stop();
}
}
});
}Promise是ES6補(bǔ)充的語(yǔ)法,解決了備選地獄的問(wèn)題。
可以把Promise看成一個(gè)狀態(tài)機(jī)。初始是pending狀態(tài),可以通過(guò)函數(shù)resolve和reject,將狀態(tài)轉(zhuǎn)換為resolved或者rejected狀態(tài),狀態(tài)一旦改變就不能再次變化。
then函數(shù)會(huì)返回一個(gè)Promise實(shí)例,并且該返回值是一個(gè)新的實(shí)例而不是之前的實(shí)例。因?yàn)镻romise規(guī)范規(guī)定pending已有狀態(tài),其他狀態(tài)是不可以改變的,如果返回的是一個(gè)相同實(shí)例的話(huà),多個(gè)then調(diào)用就失去了意義了。對(duì)于then來(lái)說(shuō),本質(zhì)上可以把它看成是flatMap
// 三種狀態(tài)
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
// promise 接收一個(gè)函數(shù)參數(shù),該函數(shù)會(huì)立即執(zhí)行
function MyPromise(fn) {
let _this = this;
_this.currentState = PENDING;
_this.value = undefined;
// 用于保存 then 中的回調(diào),只有當(dāng) promise
// 狀態(tài)為 pending 時(shí)才會(huì)緩存,并且每個(gè)實(shí)例至多緩存一個(gè)
_this.resolvedCallbacks = [];
_this.rejectedCallbacks = [];
_this.resolve = function (value) {
if (value instanceof MyPromise) {
// 如果 value 是個(gè) Promise,遞歸執(zhí)行
return value.then(_this.resolve, _this.reject)
}
setTimeout(() => { // 異步執(zhí)行,保證執(zhí)行順序
if (_this.currentState === PENDING) {
_this.currentState = RESOLVED;
_this.value = value;
_this.resolvedCallbacks.forEach(cb => cb());
}
})
};
_this.reject = function (reason) {
setTimeout(() => { // 異步執(zhí)行,保證執(zhí)行順序
if (_this.currentState === PENDING) {
_this.currentState = REJECTED;
_this.value = reason;
_this.rejectedCallbacks.forEach(cb => cb());
}
})
}
// 用于解決以下問(wèn)題
// new Promise(() => throw Error('error))
try {
fn(_this.resolve, _this.reject);
} catch (e) {
_this.reject(e);
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
var self = this;
// 規(guī)范 2.2.7,then 必須返回一個(gè)新的 promise
var promise2;
// 規(guī)范 2.2.onResolved 和 onRejected 都為可選參數(shù)
// 如果類(lèi)型不是函數(shù)需要忽略,同時(shí)也實(shí)現(xiàn)了透?jìng)?
// Promise.resolve(4).then().then((value) => console.log(value))
onResolved = typeof onResolved === 'function' ? onResolved : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => throw r;
if (self.currentState === RESOLVED) {
return (promise2 = new MyPromise(function (resolve, reject) {
// 規(guī)范 2.2.4,保證 onFulfilled,onRjected 異步執(zhí)行
// 所以用了 setTimeout 包裹下
setTimeout(function () {
try {
var x = onResolved(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
});
}));
}
if (self.currentState === REJECTED) {
return (promise2 = new MyPromise(function (resolve, reject) {
setTimeout(function () {
// 異步執(zhí)行onRejected
try {
var x = onRejected(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
});
}));
}
if (self.currentState === PENDING) {
return (promise2 = new MyPromise(function (resolve, reject) {
self.resolvedCallbacks.push(function () {
// 考慮到可能會(huì)有報(bào)錯(cuò),所以使用 try/catch 包裹
try {
var x = onResolved(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (r) {
reject(r);
}
});
self.rejectedCallbacks.push(function () {
try {
var x = onRejected(self.value);
resolutionProcedure(promise2, x, resolve, reject);
} catch (r) {
reject(r);
}
});
}));
}
};
// 規(guī)范 2.3
function resolutionProcedure(promise2, x, resolve, reject) {
// 規(guī)范 2.3.1,x 不能和 promise2 相同,避免循環(huán)引用
if (promise2 === x) {
return reject(new TypeError("Error"));
}
// 規(guī)范 2.3.2
// 如果 x 為 Promise,狀態(tài)為 pending 需要繼續(xù)等待否則執(zhí)行
if (x instanceof MyPromise) {
if (x.currentState === PENDING) {
x.then(function (value) {
// 再次調(diào)用該函數(shù)是為了確認(rèn) x resolve 的
// 參數(shù)是什么類(lèi)型,如果是基本類(lèi)型就再次 resolve
// 把值傳給下個(gè) then
resolutionProcedure(promise2, value, resolve, reject);
}, reject);
} else {
x.then(resolve, reject);
}
return;
}
// 規(guī)范 2.3.3.3.3
// reject 或者 resolve 其中一個(gè)執(zhí)行過(guò)得話(huà),忽略其他的
let called = false;
// 規(guī)范 2.3.3,判斷 x 是否為對(duì)象或者函數(shù)
if (x !== null && (typeof x === "object" || typeof x === "function")) {
// 規(guī)范 2.3.3.2,如果不能取出 then,就 reject
try {
// 規(guī)范 2.3.3.1
let then = x.then;
// 如果 then 是函數(shù),調(diào)用 x.then
if (typeof then === "function") {
// 規(guī)范 2.3.3.3
then.call(
x,
y => {
if (called) return;
called = true;
// 規(guī)范 2.3.3.3.1
resolutionProcedure(promise2, y, resolve, reject);
},
e => {
if (called) return;
called = true;
reject(e);
}
);
} else {
// 規(guī)范 2.3.3.4
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// 規(guī)范 2.3.4,x 為基本類(lèi)型
resolve(x);
}
}這里來(lái)解析一道[] == ![] // -> true譯文,下面是這個(gè)表達(dá)式為何為true的步驟
// [] 轉(zhuǎn)成 true,然后取反變成 false [] == false // 根據(jù)第 8 條得出 [] == ToNumber(false) [] == 0 // 根據(jù)第 10 條得出 ToPrimitive([]) == 0 // [].toString() -> '' '' == 0 // 根據(jù)第 6 條得出 0 == 0 // -> true ===在開(kāi)發(fā)中,對(duì)于預(yù)先返回的code,可以通過(guò)==去判斷
前者存儲(chǔ)在棧上,另外存儲(chǔ)在堆上
如果JS是門(mén)多線(xiàn)程的語(yǔ)言話(huà),我們?cè)诙鄠€(gè)線(xiàn)程中處理DOM就可能會(huì)發(fā)生問(wèn)題(一個(gè)線(xiàn)程),因?yàn)镴S是門(mén)非雙向單線(xiàn)程語(yǔ)言,因?yàn)樵谧畛跏荍S就是為了和瀏覽器交互而產(chǎn)生的。中新加二進(jìn)制,另一個(gè)線(xiàn)程中刪除例程),當(dāng)然可以約會(huì)讀寫(xiě)鎖解決這個(gè)問(wèn)題。
JS在執(zhí)行的過(guò)程中會(huì)產(chǎn)生執(zhí)行環(huán)境,這些執(zhí)行環(huán)境會(huì)被順序的加入到執(zhí)行棧中。如果遇到異步的代碼,會(huì)被掛起并加入到Task(有多種task)少量中。一旦執(zhí)行棧為空,則將會(huì)Event Loop從Task中間中拿出需要執(zhí)行的代碼并加入執(zhí)行棧中執(zhí)行,所以本質(zhì)上來(lái)說(shuō)JS中的異步還是同步行為
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
console.log('script end');代碼以上雖然setTimeout延時(shí)為0,其實(shí)還是異步。的英文這因?yàn)镠TML5標(biāo)準(zhǔn)規(guī)定這個(gè)函數(shù)第二個(gè)參數(shù)不得小于4毫秒,不足會(huì)自動(dòng)增加。所以setTimeout還是會(huì)在script end之后打印。
不同的任務(wù)源會(huì)被分配到不同的Task層次中,任務(wù)源可以分為微任務(wù)(microtask)和宏任務(wù)(macrotask)。在ES6規(guī)范中,microtask稱(chēng)為工作,macrotask稱(chēng)為task。
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
new Promise((resolve) => {
console.log('Promise')
resolve()
}).then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
// script start => Promise => script end => promise1 => promise2 => setTimeout以上代碼雖然setTimeout寫(xiě)在Promise之前,但是因?yàn)镻romise屬于微任務(wù)而setTimeout屬于宏任務(wù),所以會(huì)有以上的打印。
微任務(wù)包括 process.nextTick,promise,Object.observe,MutationObserver
宏任務(wù)包括 script,setTimeout,setInterval,setImmediate,I/O,UI renderin
很多人有個(gè)誤區(qū),認(rèn)為微任務(wù)快于宏任務(wù),其實(shí)是錯(cuò)誤的。因?yàn)楹耆蝿?wù)中包括了script,瀏覽器會(huì)先執(zhí)行一個(gè)宏任務(wù),然后有異步代碼的話(huà)就先執(zhí)行微任務(wù)
所以正確的一次Event loop順序是這樣的
執(zhí)行同步代碼,這屬于宏任務(wù)
執(zhí)行棧為空,查詢(xún)是否有微任務(wù)需要執(zhí)行
執(zhí)行所有微任務(wù)
必要的話(huà)渲染 UI
然后開(kāi)始下一輪Event loop,執(zhí)行宏任務(wù)中的異步代碼
通過(guò)上述的 Event loop順序可知,如果宏任務(wù)中的異步代碼有大量的計(jì)算和需要操作DOM的話(huà),為了更換的界面響應(yīng),我們可以把操作DOM放入微任務(wù)中
JS是單線(xiàn)程的,所以setTimeout的誤差實(shí)際上是無(wú)法被完全解決的,原因有很多,可能是某些中的,有可能是瀏覽器中的各種事件導(dǎo)致。這也是為什么頁(yè)面開(kāi)久了,定時(shí)器會(huì)不準(zhǔn)的原因,當(dāng)然我們可以通過(guò)一定的辦法去減少這個(gè)誤差。
// 以下是一個(gè)相對(duì)準(zhǔn)備的倒計(jì)時(shí)實(shí)現(xiàn)
var period = 60 * 1000 * 60 * 2
var startTime = new Date().getTime();
var count = 0
var end = new Date().getTime() + period
var interval = 1000
var currentInterval = interval
function loop() {
count++
var offset = new Date().getTime() - (startTime + count * interval); // 代碼執(zhí)行所消耗的時(shí)間
var diff = end - new Date().getTime()
var h = Math.floor(diff / (60 * 1000 * 60))
var hdiff = diff % (60 * 1000 * 60)
var m = Math.floor(hdiff / (60 * 1000))
var mdiff = hdiff % (60 * 1000)
var s = mdiff / (1000)
var sCeil = Math.ceil(s)
var sFloor = Math.floor(s)
currentInterval = interval - offset // 得到下一次循環(huán)所消耗的時(shí)間
console.log('時(shí):'+h, '分:'+m, '毫秒:'+s, '秒向上取整:'+sCeil, '代碼執(zhí)行時(shí)間:'+offset, '下次循環(huán)間隔'+currentInterval) // 打印 時(shí) 分 秒 代碼執(zhí)行時(shí)間 下次循環(huán)間隔
setTimeout(loop, currentInterval)
}
setTimeout(loop, currentInterval)[1, [2], 3].flatMap(v => v) // -> [1, 2, 3]
如果想將一個(gè)多維整數(shù)徹底的降維,可以這樣實(shí)現(xiàn)
const flattenDeep = (arr) => Array.isArray(arr) ? arr.reduce( (a, b) => [...a, ...flattenDeep(b)] , []) : [arr] flattenDeep([1, [[2], [3, [4]], 5]])
這個(gè)問(wèn)題通常可以通過(guò)JSON.parse(JSON.stringify(object))來(lái)解決
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE但是該方法也是有局限性的:
會(huì)忽略 undefined
會(huì)忽略 symbol
不能序列化函數(shù)
不能解決循環(huán)引用的對(duì)象
let obj = {
a: 1,
b: {
c: 2,
d: 3,
},
}
obj.c = obj.b
obj.e = obj.a
obj.b.c = obj.c
obj.b.d = obj.b
obj.b.e = obj.b.c
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)在遇到函數(shù),undefined或者symbol的時(shí)候,該對(duì)象也不能正常的序列化
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}但是在通常情況下,復(fù)雜數(shù)據(jù)都是可以序列化的,所以這個(gè)函數(shù)可以解決大部分問(wèn)題,并且該函數(shù)是內(nèi)置函數(shù)中處理深拷貝性能移動(dòng)的。當(dāng)然如果你的數(shù)據(jù)中含有以上某種情況下,可以使用lodash的深拷貝函數(shù)
typeof對(duì)于基本類(lèi)型,除了null都可以顯示正確的類(lèi)型
typeof 1 // 'number' typeof '1' // 'string' typeof undefined // 'undefined' typeof true // 'boolean' typeof Symbol() // 'symbol' typeof b // b 沒(méi)有聲明,但是還會(huì)顯示 undefined
typeof 對(duì)于對(duì)象,除了函數(shù)都會(huì)顯示 object
typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'對(duì)于null來(lái)說(shuō),雖然它是基本類(lèi)型,但是會(huì)顯示object,這是一個(gè)存在很久了的Bug
typeof null // 'object'
instanceof 可以正確的判斷對(duì)象的類(lèi)型,因?yàn)閮?nèi)部機(jī)制是通過(guò)判斷對(duì)象的原型鏈中是不是能找到類(lèi)型的 prototype
我們也可以試著實(shí)現(xiàn)一下 instanceof
function instanceof(left, right) {
// 獲得類(lèi)型的原型
let prototype = right.prototype
// 獲得對(duì)象的原型
left = left.__proto__
// 判斷對(duì)象的類(lèi)型是否等于類(lèi)型的原型
while (true) {
if (left === null)
return false
if (prototype === left)
return true
left = left.__proto__
}
}到此,關(guān)于“分析web前端中的JS”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
網(wǎng)站題目:分析web前端中的JS
本文網(wǎng)址:http://chinadenli.net/article10/jijdgo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供App開(kāi)發(fā)、電子商務(wù)、品牌網(wǎng)站建設(shè)、面包屑導(dǎo)航、品牌網(wǎng)站制作、網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)