箭头函数和普通函数的区别!
- 箭头函数没有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重叠
-
清除浮动