箭頭函式和普通函式的區別!
- 箭頭函式沒有prototype(原型),所以箭頭函式本身沒有this
let a = ()=>{}
console.log(a.prototype) // undefined
複製程式碼
- 箭頭函式的this指向在定義的時候繼承自外層第一個普通函式的this。
let a,
barObj = {msg: 'bar'},
fooObj = { msg: 'foo' };
function foo(){
a();
}
function bar(){
a = ()=>{console.log(this)}
};
bar.call(barObj);
foo.call(fooObj);
// {msg: 'bar'}
複製程式碼
- 如果箭頭函式外層沒有普通函式,嚴格模式和非嚴格模式下它的this都會指向window
let foo = ()=>{console.log(this)};
foo(); // window
'use strict'
let foo = ()=>{console.log(this)};
foo(); // window
複製程式碼
- 箭頭函式本身的this指向不能改變,但可以修改它要繼承的物件this。
let foo = ()=>{console.log(this)};
let fooObj = {msg: 'fooObj'};
foo.call(fooObj); // window
let a,
barObj = {msg: 'bar'},
fooObj = { msg: 'foo' };
function foo(){
a();
}
function bar(){
a = ()=>{console.log(this)}
};
bar.call(barObj);
foo.call(fooObj);
// {msg: 'bar'}
複製程式碼
- 箭頭函式的this指向全域性,使用aguments會報未生命的錯誤。
let foo = ()=>
foo(); //Uncaught ReferenceError: arguments is not defined
複製程式碼
- 箭頭函式的this指向普通函式時,它的arguments指向普通函式的arguments
function foo(){
console.log(arguments);
let bar = ()=>{
console.log(arguments);
}
bar();
}
foo(1,2,3); // [1,2,3] [1,2,3]
複製程式碼
- 使用new呼叫函式會報錯,因為箭頭函式沒有constructor
let a = ()=>{}
let b = new a(); // a is not a constructor
複製程式碼
- 箭頭函式不支援new.target
let a = ()=>{
console.log(new.target)
}
a(); // new.target expression is not allowed here
複製程式碼
- 箭頭函式不支援重新命名函式引數,普通函式的函式引數支援重新命名
function fun1(a, a){
console.log(a, arguments)
}
let fun2 = (a, a) => {
console.log(a);
} // Uncaught SyntaxError: Duplicate parameter name not allowed in this context
fun1(1,2); // 2 [1,2]
複製程式碼
- 箭頭函式相對於普通函式語法更簡潔優雅。
instanceof 實現原理
function _instanceof(leftValue, rightValue){
let leftValue = leftValue.__proto__;
let rightValue = rightValue.prototype;
while(true){
if(leftValue == null){
return false;
}
if(leftValue === rightValue){
return true;
}
leftValue = leftValue.__proto__;
}
}
複製程式碼
function Foo() {
}
Object instanceof Object // true
Function instanceof Function // true
Function instanceof Object // true
Foo instanceof Foo // false
Foo instanceof Object // true
Foo instanceof Function // true
複製程式碼
promise.all函式實現
promise.all = funciton(promis){
let arr =[];
let i = 0;
let proccess = function(reuslt, index, resolve){
arr[index] = result;
i++;
if(i == promis.length){
return resolve(arr);
}
}
return new Promise( (resolve,rejcet)=>{
for(let i = 0; i < promis.length; i++){
promis[i].then( (result)=>{proccess(result, index, resolve)} , (err)=>{reject(err)} );
}
} )
}
複製程式碼
bind方法實現
Function.prototype._bind = function(context, ...args){
if(typeof context !== 'function'){
throw new Error('Function.prototype.bind - what is trying to be bound is not callable')
}
let self = this;
let bound = function(){
return this.apply(context, args)
}
return bound
}
複製程式碼
如果_bind 返回的函式被作為建構函式來使用,此時 _bind 指定的this值會失效,但傳入的引數依然生效。改版一:
Function.prototype._bind = function(context, ...args){
if(typeof context !== 'function'){
throw new Error('Function.prototype.bind - what is trying to be bound is not callable')
}
let self = this;
let bound = function(...arr){
// 判斷是否是作為建構函式
//是的話,返回this 指向new建立的例項
//否的話,指向context
return self.apply(context instanceof bound ? this : context, [].concat(args, arr));
}
//返回函式的prototype 為 繫結函式的prototype,例項講究可以繼承繫結函式的原型中的值
bound.prototype = this.prototype;
return bound;
}
複製程式碼
因為 bound.prototype = this.prototype,如果例項函式修修改prototype,也 修改了繫結函式的prototype。
function bar() {}
var bindFoo = bar.bind2(null);
// 修改 bindFoo 的值
bindFoo.prototype.value = 1;
// 導致 bar.prototype 的值也被修改了
console.log(bar.prototype.value) // 1
複製程式碼
改版二:
Function.prototype._bind = function(context, ...args){
if(typeof context !== 'function'){
throw new Error('Function.prototype.bind - what is trying to be bound is not callable');
}
let self = this;
let fun = function(){};
let bound = function(...arr){
return self.apply(context instanceof fun ? this : context, [].concat(args, arr) )
}
fun.prototype = self.prototype;
bound.prototype = fun.prototype;
return bound;
}
複製程式碼
防抖函式
function debounce(fn, delay, immediate){
let timer = null;
return (...args)=>{
let context = this;
if(timer){ clearTimeout(timer) }
if(immediate){
if(timer){return}
fn.apply(context, args);
timer = setTimeout(()=>{
timer = null;
},delay)
}else {
timer = setTimeout( ()=>{
fn.apply( context, args );
} , delay)
}
}
}
複製程式碼
截流函式
function throttle(fn, delay, mustRunDelay ){
let c = null;
let start = null;
return (...args)=>{
let context = this;
let current = new Date();
if(timer){ clearTimeout(timer) }
if(!start){
start = current;
}
if(mustRunDelay && current - now >= mustRunDelay){
fn.apply(context, args);
start = current;
}else{
tiemr = setTimeout(()=>{
fn.apply(context, args);
start = current;
}, delay)
}
}
}
複製程式碼
深克隆
function deepClone(obj, hash = new Map()){
if( obj instanceof RegExp ){return new RegExp(obj)}
if( obj instanceof Date ){ return new Data(obj) }
if( obj == null || typeof obj !== 'object' ){
return obj
}
if( hash.has(obj) ){
return hash.get(obj);
}
let t = new obj.constructor();
hash.set( obj, t );
for(let key in obj){
if( obj.hasOwnProperty( key ) ){
t[key] = deepClone(obj[key], hash );
}
}
return t;
}
複製程式碼
js equal函式
let USUAL_TYPE = ['[object Number]', '[object String]', '[object Boolean]'];
let toString = Object.prototype.toString;
function equal(v1, v2, isStrongType){
let type1 = toString.call(v1);
let type2 = toString.call(v2);
if(isStrongType || ( USUAL_TYPE.indexOf(type1) == -1 || USUAL_TYPE.indexOf(type2) )){
if(type1 !== type2){
return false;
}
}
if(Array.isArray(v1)){
if(v1.length !== v2.length ){return false}
for(let i = 0; i<v1.length; i++){
if(!equal(v1[i], v2[i], isStrongType)){return false}
}
}else if( toString.call(v1) === '[object Object]' ){
if(Object.keys(v1).length !== Object.keys(v2).length){return false}
for(let key in v1){
if(!(v1.hasOwnProperty(key) && v2.hasOwnProperty(key) ) || !equal(v1[key] , v2[key], isStrongType)) {return false}
}
}else{
return isStrongType ? v1 === v2 : v1 == v2;
}
return true
}
複製程式碼
CSS實現一個三角形
<div></div>
div{
border-top: 10px solide transparent;
border-left: 10px solide transparent;
border-right: 10px solide transparent;
border-bottom: 10px solide #000;
}
複製程式碼
promis實現
class _Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value)=>{
if(!this.state === 'pending' )return
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn=>fn());
}
let reject = (reason)=>{
if(!this.state === 'pending' )return
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
try{
executor(resolve, reject);
}catch(err){
resolve(err);
}
}
then(onFulfilled, onRejected){
console.log(onFulfilled, 'onFulfilled')
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value=>value;
onRejected = typeof onRejected === "function" ? onRejected: err=>{throw err}
let promise2 = new _Promise((resolve, reject)=>{
if(this.state === "fulfilled"){
setTimeout(()=>{
try{
let x = onFulfilled(this.value);
console.log(onFulfilled);
this.resolvePromise( promise2, x, resolve, reject );
}catch(err){
reject(err);
}
}, 0)
}
if(this.state === "rejected"){
setTimeout(()=>{
try{
let x = onRejected(this.reason);
this.resolvePromise( promise2, x, resolve, reject );
}catch(err){
reject(err);
}
}, 0);
}
if(this.state === "pending" ){
this.onFulfilledCallbacks.push( ()=>{
setTimeout(()=>{
try{
let x = onFulfilled(this.value);
this.resolvePromise( promise2, x, resolve, reject );
}catch(err){
reject(err);
}
}, 0)
} );
this.onRejectedCallbacks.push(()=>{
setTimeout(()=>{
try{
let x = onRejected(this.reason);
this.resolvePromise( promise2, x, resolve, reject );
}catch(err){
reject(err);
}
}, 0)
});
}
});
return promise2
}
resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
return reject( 'Chaining cycle detected for promise' );
}
let called;
if(x != null && (typeof x === "object" || typeof x === "function")){
try{
let then = x.then;
if(typeof then ==='function' ){
then.call(x, y => {
if(called)return
called = true;
this.resolvePromise( promise2, y, resolve, reject );
}, err=>{
if(called)return
called = true;
reject(err);
})
}else{
if(called)return;
resolve(x);
called = true;
}
}catch(err){
if(called)return;
called = true;
reject(err);
}
}else{
resolve(x);
}
}
}
_Promise.resolve = function(val){
return new _Promise((resolve, reject)=>{
resolve(val);
})
}
_Promise.reject = function(err){
return new _Promise((resolve, reject)=>{
reject(err);
})
}
_Promise.race = function(promises){
return new _Promise((resolve, reject)=>{
for(let i = 0; i < promises.length; i++){
promises[i].then((val)=>{
resolve(val);
}, (err)=>{
reject(err);
})
}
})
}
_Promise.all = function(promises){
let arr = [];
let num = 0;
function process(val, index, resolve){
arr[index] = val;
num++
if(num == promises.length ){
resolve(arr)
};
}
return new _Promise((resolve,reject)=>{
for(let i = 0; i < promises.length; i++){
promises[i].then(val=>{
process(val, i, resolve);
}, err=>{
reject(err)
});
}
})
}
複製程式碼
釋出訂閱
let EventEmitter = {
_list: {},
on: function(event, fn){
_list[event] ? _list[event].push(fn) : _list[event] = [fn];
},
emit: function(event, ...args){
let fns = _list[event];
if(!fns)return
for(let i = 0; i < fns.length; i++ ){
fns[i].apply(this, args);
}
},
off: funciton(event, fn){
let fns = _list[event];
if(!fns)return true;
if(!fn){
delete _list[event]
}else{
for(let i = 0; i < fns.length; i++){
if(fns[i] === fn){
fns.split(i, 1);
}
}
}
return true
}
}
複製程式碼
輸入url都發生了什麼
- 使用者輸入合成url 搜尋內容,還是如何url規則。合成完整的url
- url強求過程 DNS解析,獲取IP地址,利用IP地址和伺服器建立TCP連結,然後發起http請求
- 計算DOM樹
- 生成DOM樹後,根據CSS樣式表,計算出DOM樹所有節點的樣式
- 計算佈局資訊,合成佈局樹。
- 生成圖層樹
- 合成執行緒將圖層分成圖塊,並在光柵化執行緒池中將圖塊轉換成點陣圖
- 合成執行緒傳送繪製圖塊命令 DrawQuad 給瀏覽器程式。
- 瀏覽器程式根據 DrawQuad 訊息生成頁面,並顯示到顯示器上。
BFC
-
內部的Box會在垂直方向,一個接一個地放置。
-
Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊。
-
每個盒子(塊盒與行盒)的margin box的左邊,與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此。
-
BFC的區域不會與float box重疊。
-
BFC就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素。反之也如此。
-
計算BFC的高度時,浮動元素也參與計算。 如何建立
-
float的值不是none
-
position的值不是static或者relative
-
display的值是inline-block、table-cell、flex、table-caption或者inline-flex
-
overflow的值部位visible BFC的作用
-
利用BFC避免margin重疊
-
清除浮動