Function.prototype.myCall = function(context, ...args) {
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
}
getMessage.myCall(obj, 'name');
當即執行getMessage方法,不過是以obj.getMessage的方式,傳入參數'name'。(obj可能壓根就沒有getMessage方法)
複製代碼
Function.prototype.myApply = function(context, args) {
context.fn = this;
const result = context.fn(...args);
delete context.fn;
return result;
}
getMessage.myApply(obj, ['name']);
複製代碼
Function.prototype.myBind = function(context, ...args) {
return () => {
return this.myApply(context, args);
}
}
const result = getMessage.myBind(obj)
result是一個函數,再執行一次纔是getMessage方法的執行結果
複製代碼
function createNew(Ctur, ...args) {
const obj = {};
obj.__proto__ = Ctur.prototype;
const ret = Ctur.apply(obj, args);
return ret instanceof Object ? ret : obj;
}
1. 建立一個空對象。
2. 將構造函數的原型繼承給這個空對象的隱式原型。
3. 在obj下執行構造函數,並傳入參數,這個時候構造函數內的this就是obj。
4. 若是這個'構造函數'沒有return對象格式的結果,返回新建立的obj。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.getName = function() {
console.log(this.name);
}
const xm = createNew(Person, 'xiaoming', 22);
複製代碼
function myInstanceOf(left, right) {
while(1) {
if(left.__proto__ === null) {
return false;
}
if(left.__proto__ === right.prototype) {
return true;
}
left = left.__proto__;
}
}
instanceof的原理就是經過原型鏈查找,因此一直向上查找左側的隱式原型__ptoto__是否等於右側顯式原型,
原型鏈的盡頭是null,沒找到就返回false。
myInstanceOf([1,2], Array); // true
複製代碼
Array.prototype.myForEach = function(fn) {
const arr = this;
for(let i = 0; i < arr.length; i++) {
fn(arr[i], i, arr);
}
}
接受一個fn回調函數,傳遞給回調函數三個參數:每項的值,下標,自身。第二個參數有人用麼?
const arr = ['a','b','c'];
arr.myForEach(item => {
console.log(item); // a b c
})
複製代碼
Array.prototype.myMap = function(fn) {
const arr = this;
const ret = [];
for(let i = 0; i < arr.length; i++) {
ret.push(fn(arr[i], i, arr));
}
return ret;
}
和forEach相似也是接受一個fn回調,不過會將回調處理的結果放入一個新的數組,
因此map回調內的每一項須要return,由於要組成新的數組結果。
const arr = ['a', 'b', 'c'];
const newArr = arr.myMap(item => { // a1 b1 c1
return item + 1; // 要return結果
})
複製代碼
Array.prototype.myFilter = function(fn) {
const arr = this;
const ret = [];
for(let i = 0; i < arr.length; i++) {
if(fn(arr[i], i, arr)) {
ret.push(arr[i]);
}
}
return ret;
}
大同小異,過濾出處理條件爲true的值。
返回數組中不重複的值:
function repeat(arr) {
return arr.myFilter((v, i, a) => {
return a.indexOf(v) === a.lastIndexOf(v);
})
}
const arr = [1,2,3,4,1,2,3,5,6,8,3];
repeat(arr); // [4,5,6,8]
複製代碼
Array.prototype.myFind = function(fn) {
const arr =this;
for(let i = 0; i < arr.length; i++) {
if(fn(arr[i], i, arr)) {
return arr[i];
}
}
}
不然返回undefined
複製代碼
你們本身寫下咯~
複製代碼
Array.prototype.myEvery = function(fn) {
const arr = this;
for(let i = 0; i < arr.length; i++) {
if(!fn(arr[i], i, arr)) {
return false;
}
}
return true;
}
複製代碼
這個相信你們都知道怎麼寫了~
複製代碼
Array.prototype.myReduce = function(fn, accumulator) {
const arr = this;
let index = 0;
if(typeof accumulator === undefined) { // 沒傳第二個參數
index = 1;
accumulator = arr[0];
}
for(let i = index; i < arr.length; i++) {
let invokedReturn = fn(accumulator, arr[i], i, arr);
accumulator = invokedReturn;
}
return accumulator;
}
通常會傳入第二個參數做爲初始值,若是沒有傳入,初始值就是數組的第一項,將處理的結果進行累計,最後返回累計的結果。
返回數組中指定參數重複的次數:
function count(arr, value) {
return arr.myReduce((f, s) => {
return Object.is(s, value) ? f + 1 : f + 0;
}, 0)
}
const arr = [1,2,3,4,1,2,3,2,1];
count(arr, 2); // 3
複製代碼
function jsonStringify(obj) {
const type = typeof obj;
if (type !== 'object') {
if (type === 'string') {
obj = '"' + obj + '"';
}
return String(obj);
} else {
const json = [];
const arr = Array.isArray(obj);
for (const k in obj) {
let v = obj[k];
const type = typeof v;
if (type === 'string') {
v = '"' + v + '"';
} else if (v === null) { // 處理null狀況
v = null
} else if (/function|undefined/.test(type)) { // 原生方法會移除function和undefined
delete obj[k];
} else {
v = jsonStringify(v); // 遞歸
}
json.push((arr ? "" : '"' + k + '":') + String(v));
}
return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}")
}
}
const obj = {
a: 'a1',
b: [1, 2, 3],
c: 22,
d: function () {},
e: Date.now(),
f: null,
g: /str/ig,
h: undefined
}
const str = jsonStringify(obj);
// {"a":"a1","b":[1,2,3],"c":22,"e":1562815128952,"f":null,"g":{}}
複製代碼
function jsonParse(str) {
return new Function('return ' + str)(); // return後有一個空格
}
很神奇有木有,直接在字符串前面加上'return '關鍵字就能夠轉爲對象。
在組件精講小冊裏有一個實例,在線vue單文件編輯器。原理就是將編輯器內的vue單文件字符串使用正則分割,
js部分將‘export default’替換爲'return '。經過new Function轉爲js對象使用。
const sum = new Function('a','b','return a + b');
sum(1, 2); // 3
const str = '{"a":"a1","b":[1,2,3],"c":22,"e":1562815128952,"f":null,"g":{}}';
jsonParse(str); //
a: "a1",
b: [1, 2, 3],
c: 22,
e: 1562815128952,
f: null,
g: {}
複製代碼
function mySetInterval(fn, interval) {
const now = Date.now;
let startTime = now();
const loop = () => {
const timer = requestAnimationFrame(loop);
if (now() - startTime >= interval) {
startTime = now();
fn(timer);
}
}
loop();
}
通常來講是不建議使用setInterval的,如內部函數複雜就不能保證必定在規定時間內自動執行。
通常是經過setTimeout模仿setInterval。那爲何要實現setInterval,
由於它內部的實現是使用requestAnimationFrame實現的,該方法自帶函數節流。
若有持續的動畫須要執行,基本會保證在16.6毫秒內執行一次,提升動畫性能並延時也是精確的。
mySetInterval(timer => {
console.log('a');
// cancelAnimationFram(timer) 能夠取消當前定時器
})
複製代碼
定時執行一次回調就取消掉,本身實現下吧~
複製代碼
還有例如Promise,節流/防抖, jsonp,深拷貝等方法要不代碼太長或者不是原生的方法,他們每個均可以寫一個單篇,就不列在這了。若有謬誤之處,萬望斧正。vue