本文共 13496 字,大约阅读时间需要 44 分钟。
// 题意是下面输入结果分别是: var num1 = 60 ; var num2 = 50 ; function foo(num,num1){ // 先看传入什么进来 // var num ; // var num1 = 50; num = 100 ; num1 = 100; num2 = 100; console.log(num); // 100 console.log(num1); // 100 console.log(num2); // 100 } // 调用foo() foo(num1,num2); console.log(num1); //60 console.log(num2); // 100 console.log(num); //报错! // 这个题目看起来很简单,但是带着带着一些坑!
在 JavaScript 中,函数也是对象,实际上,JavaScript 里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供 JavaScript 引擎访问的内部属性。其中一个内部属性是 [[Scope]],由 ECMA-262 标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问
下面具体分析下关于这个题
var num ; var num1 = 60;
在函数中,一旦var
之后,那么就随之在函数内部变成了局部作用域,对于没有var的num2
而言,属于隐式全局可以变量,所以结果是可以访问到外部,故它可以改变外面的值。这也就解释来为什么结果是这个样子了。// 第2题值类型与引用类型的传递 function Person(name, age, salary){ this.name = name; this.age = age; this.salary = salary;}function f1(person) { // 调用f1 // var person = p; // 两个变量的地址指向同一个对象,改变p.name ='ls' person.name = 'ls'; // 堆内存重新开辟一个空间 // person 改变指向,但是p没有改变指向 person = new Person('aa', 18, 10);}var p = new Person('zs', 18, 1000);console.log(p.name) // 'zs'f1(p);console.log(p.name); // 'ls'/** * 栈内存中--- 值的存储 * 堆内存 --- 引用类型存储 */
在JS中,每一个数据都需要一个内存空间。内存空间又被分为两种,栈内存(stock)与堆内存(heap)。
Number
,String
,Boolean
,Null
,Undefined
var a1 = 0; // 栈 var a2 = 'this is string'; // 栈var a3 = null; // 栈var b = { m: 20 }; // 变量b存在于栈中,{m: 20} 作为对象存在于堆内存中var c = [1, 2, 3]; // 变量c存在于栈中,[1, 2, 3] 作为对象存在于堆内存中
因此当我们要访问堆内存中的引用数据类型时,实际上我们首先是从栈中获取了该对象的地址引用(或者地址指针),然后再从堆内存中取得我们需要的数据
分析到这里,我想已经明白了上面那一道题的具体思路了,如果不了解,下附一张图:
(本小节完!)
var foo = 'hello-world-javaScript';// var arr = foo.split('-');// for (var i = 0; i0){// // console.log(arr[i].charAt(0));// // 把首字母转成大写// // console.log(arr[i].charAt(0).toUpperCase());// // 除掉第一个字母,然后进行拼接// // console.log(arr[i].charAt(0).toUpperCase() + arr[i].substr(1,arr[i].length));// // 重新赋值给arr[i]// arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1,arr[i].length);// // console.log(arr[i]);// }// } // 已经成功的转成大写的数组形式 // console.log(arr)// 最后使用join 方式将数组转成字符串。// console.log(arr.join('')) // 已经成功的转成驼峰命名// .charAt(0).toUppercase()+ arr[i].subStr(1,arr[i].length) //拿到字符的第一个字母,转成大写。// // 封装成函数 function toString(str){ // 第一步将字符串专程数组 var arr = str.split('-'); // 第一步循环遍历 for (var i=0 ; i < arr.length ; i ++ ){ // 因为要除去第一个单词不用遍历。 所以不要arr[0] if (i > 0) { // 一步到位,具体看上面演示 arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1,arr[i].length); } } // 将数组重新转成字符串 return arr.join(''); }//test console.log(toString(foo));
本次方法用到了str.split()
字符串分割方法。 字符串的str.charAt()
方法获取字符串的第一个字母 。使用字符串的方式截取字符str.substr()
。 还使用了arr.join(''). 将数组专程字符串。
(本节完~)
// 如何对数组进行冒泡排序 var arr = [10,3,4,5,6,1,2,3];// 循环比较的轮数 for (var i=0; iarr[j+1]) { // 如果成立的话,交换两个数,需要借助第三方变量来实现 // 第一步,将arr[j] 先存放到temp 中。 var temp = arr[j]; // 第二步。将arr[j+1]的值赋值给arr[j]// arr[j] = arr[j+1]; // 第三步,将存放的arr[j]的值交给arr[j+1] arr[j+1] =temp; } }}// 到这已经完成了冒泡排序 console.log(arr);
// 需求是实现数组的反转 var arr = [1,3,4,5,6,7,8,9];// 思路: 将第一个数字和最后一个数组交换 ,一共需要交换的次数就是数组的一半 for (var i=0; i
当然这个是最原始的反转方式来,数组已经提供来原生API(Array.prototype.reverse()
)可以使用
(本节完!)
// 业务要求数组去重 var arr = [1,3,4,5,,4,4,4,4,55,5,5];// 设置一个新的数组var newArr = [];// 首先将数组的第一个值赋值给newArr newArr[0] = arr[0];// 循环遍历数组arr for (var i=0 ; i< arr.length ; i++){ // 循环遍历数组是否和新数组中的一致 for(var j=0; j
总结,数组去重的方式多样,本人更加喜欢Array.prototype.indexOf()
这种方式去重 。
需要首先搞明白物理像素和css像素
设备像素(devie pixel
是物理概念,指的是设备的物理像素。css像素 (CSS pixel)
CSS 像素是web编程中的概念,指的是Css中的逻辑像素。在Css中,长度可以分为两类,绝对单位以及相对单位。px
是一个相对的单位,相对的是设备的像素。 像素比 = 物理像素/css像素// 获取当前的物理像素var dpr = window.devicePixeRatio;// 设置物理的像素的缩放比 var scale = 1/dpr;// 获取meta var metaNode = document.querySelect('meta[name="viewport"]');// 设置初始缩放比 metaNode.setAtttribute('content','widht=divce-width,inital-scale='+scale+'');
直接看代码
.box { position: relative; width: 100px; /* */ height: 100px; } .box::before{ content: ''; position: absolute; left: 0; bottom: 0; width: 100%; height: 1px; background-color: #000; } /* 媒体查询 */ @media screen and (-webkit-min-device-pixel-ratio:2){ .box::before{ transform: scaleY(0.5) } } @media screen and (-webkit-min-device-pixel-ratio:3){ .box::before{ transform: scaleY(0.3333) } }
此类方式根据媒体查询来实现哦
以上方法就实现1px 物理像素。
本次采用了四种方式,看代码
.box1{ width: 400px; height: 400px; background-color: red; /* 方式1 2 3 需要解开 */ /* position: relative; */ /* 方式4 */ display: flex; /* 水平方向上居中 */ justify-content: center; /* 垂直方向向居中 */ align-items: center; } .box2{ width: 100px; height: 100px; background-color: pink; /* position: absolute; */ /* 方式1 */ /* top: 50%; left: 50%; margin-left: -50px; margin-top: -50px; */ /* 方式2 */ /* left: 0;top:0; right: 0;bottom: 0; margin:auto; */ /* 方式3 */ /* top: 50%; left: 50%; transform: translate(-50%,-50%); */ }
position
方式。。在使用方式2的时候,记得对margin:atuo
。不然没法实现。。第四种方式是flex
布局方式。还有一种比较老版本的的居中方式是:*{ display:-webkit-box; -webkit-box-pack:center; -webkit-box-align:center;}
( 本节完!)
css
实现▶️三角形 直接上代码.box{ width:0; height:0; border:100px solid; border-top-color:red; /* border-right-color:green; */ /* border-bottom-color:pink; */ /* border-left-color:purple; */ border-right-color:transparent; border-bottom-color:transparent; border-left-color:transparent;}
利用边框的特点。而且每一条边框都可以设置不同的大小,或者颜色等。去掉中心内容,如果设置不同的颜色,就可以实现四个三角形。如果只需得到一个三角 形,就给其他的三个边都设置transparent
。
(本节完!)
什么是rem ?
rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem大家一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。
Document
(本小节完~)
function Foo (){ getName = function () { console.log(1) } return this }Foo.getName = function () { console.log(2)}Foo.prototype.getName = function() { console.log(3) }var getName = function () {console.log(4)}function getName() { console.log(5) }// 输出结果 Foo.getName() //2 👌getName() // 5 ❌ 4 Foo().getName() // ❌ (Foo()).getName() ----> window.getName() 1getName() // 5 ❌ 1new Foo.getName() //2 👌 new(Foo.getName)() ----->> new (function(){console.log(2)}) 2new Foo().getName()// ❌ (new Foo()).getName() ---> foo.getName() 3new new Foo().getName() // ❌ new ((new Foo()).getName)() ---> new (foo.getName)() ---> new (function(){ console.log(3)})() //3
function Foo (){ getName = function () { console.log(1) } return this }// 变量声明的提升 // 和函数自定义名字冲突// var getName // 函数的提升// 变量和函数提后,继续从⬆️到⬇️执行代码, 发现后面的函数getName, 会重新赋值// function getName() { console.log(5) }Foo.getName = function () { console.log(2)}Foo.prototype.getName = function() { console.log(3) }getName = function () {console.log(4)}
/** * 变量提升和函数提升 * 1. 函数提升(整体的提升) * 2. var 变量提升(声明的提升) * 3. 重新赋值 * 4. 变量的查找规则,沿着作用域链去找 * 5. 点的优先级关系最高 * 6. 实例对象找属性。隐式原型链查找~ * 7. 变量和函数自定义冲突,保留函数 * */
(本节完!)
函数节流的含义: 让被执行函数在指定的时间内被触发,而不是时刻被触发。对于时刻被触发的函数有限制的作用,这样做的好处可以极大的提升浏览器的性能。
function throttle(fn, delay){ // fn 执行函数 , delay 延迟时间 // 设置一个时间变量。 记录上一次时间 let lastTime = 0 return function(){ // 记录当前的时间戳 let currentTime = Date.now() //判断当前时间减去记录上一次的时间,是否大于延迟时间 if( currentTime - lastTime > delay){ fn.call(this) // 将当前时间赋值给上一次 lastTime = currentTime } } } // test document.addEventListener('scroll',throttle(function(){console.log('被触发了'+ Date.now())},1000))
同源策略
跨域
如何解决跨域
jsonp
script
标签,动态创建script// 创建script var script = document.createElement('script');// 设置回调函数 function getData(data){ // 数据请求回来时触发 console.log(data);}// 设置script的src属性,设置请求地址 script.src = '请求地址';// 让script生效 document.body.appendChild(script);
概括node事件的轮询机制,分为6个阶段。借助libuv
实现。
setImmediate函数
,会直接进入到下一个check阶段 如果之前没有设置过setImmediate函数
,在当前poll阶段等待,直到轮询队列添加到回调函数,就去第一个情况执行 如果定时器到点了也会去下一个阶段setImmediate
设置的回调函数process.nextTick()在任意阶段都可以优先执行。
注意 这五个步骤,不一定按顺序执行,可能反复执行,或者执行多次布局和渲染,往往在实际页面中,这些步骤会执行多次。
(本节完)
解释闭包
闭包形成的条件
闭包的优点
使用闭包需要注意:
// 简单的闭包形成function foo(){ var count = 1; function(){ console.log(count); }}// 一个函数嵌套着另一个函数,且内部函数访问外部函数的局部变量,于是产生了闭包问题。
经典面试题
function fun (n,o){ console.log(o); return { fun:function(m){ return fun(m,n) } }}var a = fun(0); a.fun(1); a.fun(2); a.fun(3); var b = fun(0).fun(1).fun(2).fun(3);var c = fun(0).fun(1)c.fun(2);c.fun(3);
答案可以自己测 也可以在6-3这个文件夹中找到01index.js中查看。
js引擎在代码正式执行的之前会做一个预处理的工作
依据
console.log(a) ; // undefined;var a = 3; fun(); // 正常输出 function fun(){ console.log('ok');}
创建变量对象
确认this的指向
创建作用域链
扩展
ECObj = { 变量对象:{'变量',' 函数','全局:window','局部:抽象的确实存在的' }, scopeChain: '父级作用域链 + 当前的变量对象', this:{ window || '调用其对象' } }
宏任务 分类: setTimeout
setInterval
requestAnimationFrame
微任务 分类:new Promise().then(回调) process.nextTick
// 宏任务上的主线程代码 (1)console.log('------------start----------')// 第二个宏任务 (最后被输出)setTimeout(() => { console.log('setTimout');}, 0);// new Promise().then() 是微任务 new Promise( (resolved, rejected) =>{ // 同步任务 ---- 主线程中的代码 (2) for (var i =0 ;i <5; i++){ console.log(i); } // resolved一旦会被调用,就会调用then方法 resolved();}).then(() =>{ // 微任务队列 console.log('Promise实例回调执行');})// 主线程代码 (3)console.log('-----------end----------');
(本节完!)
axios
是基于promise
用于浏览器和nodejs的一个http客户端,主要是用于向后台发送请求的,还有就是在请求中做更多的控制
如以下控制:
前两者都是支持promise语法,后者默认使用的是callback方式
fetch
本质上脱离的xhr是新的语法(有自己的特性,默认不穿cookie 不能像xhr这样去监听请求的进度)
axios
基本用法
axios.get('url').then( () =>{}).catch(()=>{})
转载地址:http://lpqni.baihongyu.com/