js高级(一)

89 阅读4分钟

image.png

以下总结只是个人看法,不足地方请见谅

一、浏览器的原理(v8内核)——js执行原理

一个页面在浏览器的运行过程,如图下:

截图.png

①首先是html和css共同运行到Attachment 。

②然后再通过Render生成每一个标签树。

③通过layout进行代码的布局,其中这里可能会有js操作,那这里就会借助js引擎帮助js操作DOM节点。

④之后就生成了完整的页面。

二、变量作用域,函数作用域

开胃知识:首先会有一个全局对象 globalObject(简称:GO),它里面有很多你会用到东西比如:window,console.log,setTimeout,String,Date等等,如下图:

1.变量作用域:

注:每次进行变量命名的时候都会先去GO对象里面找看有没有这个变量,真是的查找路径是沿着作用域链来查找的

截图 (1).png

var name1;   
console.log(name1);//undefined //一般不要使用name

2.函数作用域:

注:每次进行函数命名的时候都会先去创建AO对象=>再去GO对象里面找看有没有这个变量

// aaa();函数提升    
function aaa() { 
  console.log(1111); 
}    
aaa();//正常执行

3.作用域链:

为什么在child函数里面还能打印出age1的值呢:原因是作用域链首先child函数调用AO没有找到age1的变量,就是继续向父级函数的AO里找age1的变量,最终找到GO,找到的话就赋值,没有的话就是提示未定义的报错。

var age1 = "18";  
age(12); 
function age(params) {   
  console.log(params);//12     
  function child() {   
    console.log(age1);//18   
  }     
child();    
}

三、闭包的定义,内存模型

1.闭包

开胃知识:闭包和高阶函数(一个函数可以接受另一个函数作为参数或者返回的值为一个函数)是密不可分的。 一个函数能访问到外层作用域函数的变量,那么他就是闭包。

几个常见的高阶函数,如下:

// 1.filter过滤   
let number = [12, 51, 65, 22, 32];  
// 原始版    
// var ordr = number.filter(function (item) { 
//   return item % 2 === 0;    
// });   
// 简化版   
var ordr = number.filter((item) => item % 2 === 0); 
console.log(ordr); // [12, 22, 32]

// 2.map映射   
// 原始版   
// var ordr1 = number.map(function (item) {   
//   return item % 2 === 0;  
// });   
// 简化版    
var ordr1 = number.map((item) => item * 10);   
console.log(ordr1); //  [120, 510, 650, 220, 320] 

// 3.reduce:累加   
var ordr2 = number.reduce(function (value, item) {  
return value + item;   
}, 0);     
console.log(ordr2); //182

2.内存

定义:分成栈(主要是执行上下文的操作)和堆(执行全局GO对象,函数AO对象,用到作用域链一些相互之间的操作。)

内存泄漏:如果一个函数不用了就会出现内存泄漏的情况(一般闭包的话可能会出现内存泄漏的问题),解决如下图:。

截图 (2).png

四、this指向

盲区:不一定是谁定义了this,就指向的谁。 箭头函数:箭头函数的this是没有的 他会去他的上一级找this

①独立函数绑定——一般指向都是window。

②隐式函数绑定——谁调用了就会被js引擎绑定到该函数的this中。

③显示绑定——call,apply,bind 指定this绑定的对象。

④new

// 1.独立函数绑定     
function fo() {   
  console.log(this);     
}       
let fn=fo();     
fn()//绑定指向都是window

// 2.隐式绑定     
var obj={       
    age:11,    
    eating:fn    
}       
obj.eating()//会被js引擎绑定到fn函数中的this中 {age:11,eating:function}

// 3.显示绑定——call,apply,bind 指定this绑定的对象  
fo.call(obj)  
fo.apply(obj)   
fo.apply('abc')

//4.特殊绑定间接函数绑定
fo.call(null)//window fo.call(undefined)//window

1.call原型源码仿写

Function.prototype.hycall=function(thisArg,...arg){  
    //在这里可以去执行调用的那个函数  
    //问题:得可以获取到时哪个函数调用到call  
    var fn =this   
    // 2.对传过来的是进行判断转成对象,防止传过来的值是非对象 
    thisArg = (thisArg !==null && thisArg !==undefined) ? Object(thisArg) : window     thisArg.fn=fn  
    thisArg.fn(...arg)  
    delete thisArg.fn 
} 
function foo() {    
  console.log('foo被执行了',this);
} 
function sum(num1,num2) {  
  console.log('sum被执行了',this,num1,num2);
} 
foo.hycall('abc') 
sum.hycall('abc',12,22)

2.apply原型源码仿写

Function.prototype.hyapply=function(thisArg,argArray){ 
    //在这里可以去执行调用的那个函数   
    //问题:得可以获取到时哪个函数调用到apply  
    var fn =this  
    // 2.对传过来的是进行判断转成对象,防止传过来的值是非对象   
    thisArg = (thisArg !==null && thisArg !==undefined) ? Object(thisArg) : window     thisArg.fn=fn 
    var result =argArray || [] //逻辑或  
    thisArg.fn(...argArray)    
    delete thisArg.fn    
    return result
} 
function foo() {   
  console.log('foo被执行了',this);
} 
function sum(num1,num2) {  
  console.log('sum被执行了',this,num1,num2);
} 
sum.hyapply('abc',[12,22])

3.bind原型源码仿写

Function.prototype.hybind=function(thisArg,...argArray){  
    // 1.获取到真是需要调用的函数    
    var fn =this  
    // 2.绑定this  
    thisArg = (thisArg !==null && thisArg !==undefined) ? Object(thisArg) : window   
    function proxyFn(...arg) {   
    thisArg.fn =fn   
    // 3.将函数放到总数组中 
    var sumArray=[...argArray,...arg]     
    var result =thisArg.fn(...sumArray)    
    delete thisArg.fn     
    return result   
}   
return proxyFn
}
function foo() {    
  console.log('foo被执行了',this);
} 
function sum(...num) {   
  console.log('sum被执行了',this,...num); 
} 
var newSum= sum.hybind('abc',12,22) 
var result =newSum(55,33)