AMD CMD CommonJS
/* AMD是RequireJS對模塊化的定義
* CMD是seaJS對模塊化的定義
* CommonJS是Node對模塊化的規(guī)范
**/
/* AMD 依賴關(guān)系前置 */
define(['./a', './b'], function (a, b) {
a.something();
b.something();
})
/* CMD 按需加載栅葡,依賴就近 */
define(function (require, exports, module) {
var a = require('./a');
a.something();
var b = require('./b');
b.something();
})
阻止默認行為和阻止冒泡
function stopDefault( e ) {
// 阻止默認瀏覽器動作(W3C)
if ( e && e.preventDefault ) {
e.preventDefault();
} else {
// IE中阻止函數(shù)器默認動作的方式
window.event.returnValue = false;
}
return false;
}
function stopBubble(e) {
// 如果提供了事件對象植兰,則這是一個非IE瀏覽器
if ( e && e.stopPropagation ) {
// 因此它支持W3C的stopPropagation()方法
e.stopPropagation();
} else {
// 否則仇祭,我們需要使用IE的方式來取消事件冒泡
window.event.cancelBubble = true;
}
}
JS數(shù)組
slice實現(xiàn)淺拷貝
var arr = ['old', 1, true, null, undefined];
var new_arr = arr.slice();
new_arr[0] = 'new';
console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]
concat實現(xiàn)淺拷貝
var arr = ['old', 1, true, null, undefined];
var new_arr = arr.concat();
new_arr[0] = 'new';
console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]
以上兩種方法只是淺拷貝感凤,如果數(shù)組元素是基本類型鳍寂,就會拷貝一份新的苍在;但是如果數(shù)組元素是對象或者數(shù)組,就只會拷貝引用(類似指針)晃虫,修改其中一個就會影響另外一個皆撩。
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}];
var new_arr = arr.concat();
new_arr[0] = 'new';
new_arr[3][0] = 'new1';
console.log(arr) // ["old", 1, true, ['new1', 'old2'], {old: 1}]
console.log(new_arr) // ["new", 1, true, ['new1', 'old2'], {old: 1}]
JSON.stringify 實現(xiàn)數(shù)組深拷貝
var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}];
var new_arr = JSON.parse(JSON.stringify(arr));
new_arr[0] = 'new';
new_arr[3][0] = 'new1';
console.log(arr) // ["old", 1, true, ['old1', 'old2'], {old: 1}]
console.log(new_arr) // ["new", 1, true, ['new1', 'old2'], {old: 1}]
手動實現(xiàn)深淺拷貝
/*淺拷貝*/
var shallowCopy = function (obj) {
// 判斷是否是數(shù)組或者對象
if (typeof obj !== 'object') {
return
}
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
/*深拷貝*/
var deepCopy = function (obj) {
if (typeof obj !== 'object') {
return
}
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj
}
數(shù)組去重
/* filter + indexOf */
function unique (arr) {
var res = arr.filter(function (item, index, array) {
return array.indexOf(item) === index;
})
return res;
}
/* ES6 */
function unique (arr) {
return [... new Set(arr)];
}
打亂數(shù)組的方法
var arr = [];
for (var i = 0; i < 100; i++) {
arr[i] = i;
}
arr.sort(function () {
return 0.5 - Math.random();
});
數(shù)組扁平化
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
console.log(flatten(arr))
柯里化
執(zhí)行add(1,2,3)(2)()就能輸出1+2+3+2=8。函數(shù)柯里化
const adder = function () {
let _args = []; // 閉包保留了對 _args 的引用
return function () {
console.log(arguments)
if (arguments.length === 0) {
return _args.reduce(function (a, b) {
return a + b;
});
}
[].push.apply(_args, arguments);
return arguments.callee;
}
};
const sum = adder();
console.log(sum); // Function
sum(100, 200)(300); // 調(diào)用形式靈活哲银,一次調(diào)用可輸入一個或者多個參數(shù)扛吞,并且支持鏈式調(diào)用
sum(400);
console.log(sum()); // 1000 (加總計算)
異步函數(shù)
由async
關(guān)鍵詞定義的函數(shù)聲明了一個可以異步執(zhí)行的函數(shù),返回一個AsyncFunction
類型的對象荆责。淺談Async/Await
async
async
—聲明一個異步函數(shù) (async function someName() {...})
- 自動將常規(guī)函數(shù)轉(zhuǎn)換成
Promise
滥比,返回值也是一個Promise
對象; - 只有
async
函數(shù)內(nèi)部的異步操作執(zhí)行完做院,才會執(zhí)行then
方法指定的回調(diào)函數(shù)盲泛; - 異步函數(shù)內(nèi)部可以使用
await
濒持。
await
await
—暫停異步的功能執(zhí)行(var result = await someAsyncCall() {...})
- 放置在
Promise
調(diào)用之前,await
強制其他代碼等待寺滚,直到Promise
完成并返回結(jié)果柑营; - 只能與
Promise
一起使用,不適用與回調(diào)村视; - 只能在
async
函數(shù)內(nèi)部使用由境。
function fetchTextByPromise () {
return new Promise(resolve => {
setTimeout(() => {
resolve('es8');
}, 2000);
});
}
async function sayHello () {
const externalFetchedText = await fetchTextByPromise();
console.log(`Hello, ${externalFetchedText}`);
}
sayHello();
bind,call蓖议,apply
call
call()
方法調(diào)用一個函數(shù), 其具有一個指定的this
值和分別地提供的參數(shù)(參數(shù)的列表)。
thisArg
- 在
fun
函數(shù)運行時指定的this
值讥蟆。需要注意的是勒虾,指定的this
值并不一定是該函數(shù)執(zhí)行時真正的this
值; - 如果這個函數(shù)處于非嚴格模式下瘸彤,則指定為
null
和undefined
的this
值會自動指向全局對象(瀏覽器中就是window對象)修然; - 值為原始值(數(shù)字,字符串质况,布爾值)的
this
會指向該原始值的自動包裝對象愕宋。
arg1, arg2, ...
- 指定的參數(shù)列表。
var foo = {
value: 'fooValue'
}
function bar() {
var value = 'barValue'
console.log(this.value)
}
bar.call(foo) // 'fooValue'
call的polyfill
- 將函數(shù)設(shè)為對象的屬性
- 執(zhí)行該函數(shù)
- 刪除該函數(shù)
/*
* 將函數(shù)設(shè)為對象的屬性 foo.bar
* 執(zhí)行該函數(shù) foo.bar()
* 刪除該函數(shù) delete foo.bar
**/
Function.prototype.myCall = function (con) {
var context = con || window
var args = []
for (var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments[' + i + ']')
}
context.fn = this
var result = eval('context.fn(' + args + ')')
delete context.fn
return result
}
apply
call()
方法的作用和 apply()
方法類似结榄,區(qū)別就是call()
方法接受的是參數(shù)列表中贝,而apply()
方法接受的是一個參數(shù)數(shù)組。
apply的polyfill
Function.prototype.myApply = function (con, arr) {
var context = con || window
context.fn = this
var result
if (!arr) {
result = context.fn()
} else {
var args = []
for (var i = 0; i < arr.length; i++) {
args.push(arr[i])
}
result = eval('context.fn(' + args + ')')
}
delete context.fn
return result
}
bind
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
- 調(diào)用綁定函數(shù)時作為this參數(shù)傳遞給目標函數(shù)的值臼朗。 如果使用
new
邻寿,new
運算符創(chuàng)建一個用戶定義的對象類型的實例或具有構(gòu)造函數(shù)的內(nèi)置對象的實例。運算符構(gòu)造綁定函數(shù)视哑,則忽略該值绣否。 - 當使用
bind
在setTimeout
中創(chuàng)建一個函數(shù)(作為回調(diào)提供)時,作為thisArg
傳遞的任何原始值都將轉(zhuǎn)換為object
挡毅。 - 如果沒有提供綁定的參數(shù)蒜撮,則執(zhí)行作用域的
this
被視為新函數(shù)的thisArg
。
arg1, arg2, ...
當綁定函數(shù)被調(diào)用時跪呈,這些參數(shù)將置于實參之前傳遞給被綁定的方法段磨。
bind的polyfill
Function.prototype.myBind = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable")
}
var self = this
var args = Array.prototype.slice.call(arguments, 1)
var fNOP = function () {}
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments)
self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs))
}
fNOP.prototype = this.prototype
fBound.prototype = new fNOP()
return fBound
}
詳解:JavaScript 之 call和apply,bind 的模擬實現(xiàn)
new
- 新生成了一個對象耗绿;
- 鏈接到原型薇溃;
- 綁定
this
; - 返回新對象缭乘。
new的polyfill
function objectFactory() {
var obj = new Object()
var constructor = [].shift.call(arguments)
obj.__proto__ = constructor.prototype
console.log(obj)
var result = constructor.apply(obj, arguments)
console.log(result)
return typeof result === 'object' ? result : obj
// 判斷返回的值是不是一個對象沐序,如果是一個對象琉用,我們就返回這個對象,如果不是策幼,我們該返回什么就返回什么邑时。
}
instanceof
instanceof
可以正確的判斷對象的類型,因為內(nèi)部機制是通過判斷對象的原型鏈中是不是能找到類型的 prototype
特姐。
instanceof的polyfill
function myInstanceOf(left, right) {
// 獲得類型的原型
var prototype = right.prototype
// 獲得對象的原型
left = left.__proto__
// 判斷對象的類型是否等于類型的原型
while (true) {
if (left === null)
return false
if (prototype === left)
return true
left = left.__proto__
}
}
檢驗類型的方法
千萬不要使用typeof
來判斷對象和數(shù)組晶丘,因為這種類型都會返回object
。
- typeof:是判斷基本類型的
Boolean
唐含,Number
浅浮,symbol
,undefined
捷枯,String
滚秩,Symbol
。對于引用類型:除function
淮捆,都返回object
郁油,null
返回object
。 - instanceof:用來判斷
A
是否是B
的實例攀痊,instanceof
檢查的是原型桐腌。 - toString:是
Object
的原型方法,對于Object
對象苟径,直接調(diào)用toString()
就能返回[Object Object]
案站。而對于其他對象,則需要通過call
/apply
來調(diào)用才能返回正確的類型棘街。