标准盒子模型:宽度=内容的宽度(content)+ border + padding 低版本IE盒子模型:宽度=内容宽度(content+border+padding)
* 什么是 BFC
BFC(Block Formatting Context)格式化上下文,是 Web 页面中盒模型布局的 CSS 渲染模式,指一个独立的渲染区域或者说是一个隔离的独立容器。
* 造成 BFC 的条件
* 浮动元素,float 除 none 之外的值 * 定位元素,position(absolute,fixed) * display 为如下其中之一的值 inline-block,table-cell,table-caption * overflow 除了 visible 之外的值(hidden,auto,scroll) * BFC 的特性 * 内部的 Box 会在垂直方向上一个接一个的放置。 * 垂直方向上的距离由 margin 决定 * bfc 的区域不会与 float 的元素区域重叠。 * 计算 bfc 的高度时,浮动元素也参与计算 * bfc 就是页面上的一个独立容器,容器里面的子元素不会影响外面元素。
不清楚浮动会发生高度塌陷:浮动元素父元素高度自适应(父元素不写高度时,子元素写了浮动后,父元素会发生高度塌陷)
* clear清除浮动(添加空div法)在浮动元素下方添加空div,并给该元素写css样式: {clear:both;height:0;overflow:hidden;} * 给浮动元素父级设置高度 * 父级同时浮动(须要给父级同级元素添加浮动) * 父级设置成inline-block,其margin: 0 auto居中方式失效 * 给父级添加overflow:hidden 清除浮动方法 * 万能清除法 after伪类 清浮动(如今主流方法,推荐使用) .float_div:after{ content:"."; clear:both; display:block; height:0; overflow:hidden; visibility:hidden; } .float_div{ zoom:1 }
span { width: 0; height: 0; border-top: 40px solid transparent; border-left: 40px solid transparent; border-right: 40px solid transparent; border-bottom: 40px solid #ff0000; }
/* css */ .line { position: relative; } .line:after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 1px; background-color: #000000; -webkit-transform: scaleY(.5); transform: scaleY(.5); } /* html */ <div class="line"></div>
左右固定,中间自适应。javascript
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { display: flex; justify-content: center; height: 200px; } .left { width: 200px; background-color: red; height: 100%; } .content { background-color: yellow; flex: 1; } .right { width: 200px; background-color: green; } </style> </head> <body> <div class="box"> <div class="left"></div> <div class="content"></div> <div class="right"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { position: relative; height: 200px; } .left { width: 200px; background-color: red; left: 0; height: 100%; position: absolute; } .content { background-color: yellow; left: 200px; right: 200px; height: 100%; position: absolute; } .right { width: 200px; background-color: green; right: 0; height: 100%; position: absolute; } </style> </head> <body> <div class="box"> <div class="left"></div> <div class="content"></div> <div class="right"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { height: 200px; } .left { width: 200px; background-color: red; float: left; height: 100%; } .content { background-color: yellow; height: 100%; } .right { width: 200px; background-color: green; float: right; height: 100%; } </style> </head> <body> <div class="box"> <div class="left"></div> <div class="right"></div> <div class="content"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { width: 400px; height: 200px; position: relative; background: red; } .content { width: 200px; height: 100px; position: absolute; top: 50%; left: 50%; margin-left: -100px; margin-top: -50px; background: green; } </style> </head> <body> <div class="box"> <div class="content"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { width: 400px; height: 200px; position: relative; background: red; } .content { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: green; } </style> </head> <body> <div class="box"> <div class="content"></div> </div> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box { width: 400px; height: 200px; background: red; display: flex; justify-content: center; align-items: center; } .content { width: 200px; height: 100px; background: green; } </style> </head> <body> <div class="box"> <div class="content"></div> </div> </body> </html>
闭包概念php
可以读取其余函数内部变量的函数。 或简单理解为定义在一个函数内部的函数,内部函数持有外部函数内变量的引用。
闭包用途css
一、读取函数内部的变量 二、让这些变量的值始终保持在内存中。不会再f1调用后被自动清除。 三、方便调用上下文的局部变量。利于代码封装。 缘由:f1是f2的父函数,f2被赋给了一个全局变量,f2始终存在内存中,f2的存在依赖f1,所以f1也始终存在内存中,不会在调用结束后,被垃圾回收机制回收。
闭包缺点html
一、因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。 二、闭包会在父函数外部,改变父函数内部变量的值。因此,若是你把父函数看成对象(object)使用,把闭包看成它的公用方法(Public Method),把内部变量看成它的私有属性(private value),这时必定要当心,不要随便改变父函数内部变量的值。
闭包应用场景vue
闭包应用场景之的setTimeoutjava
//setTimeout传递的第一个函数不能带参数 setTimeout((param) => { alert(param) }, 1000); //经过闭包能够实现传参效果 function func(param) { return function() { alert(param) } } var f1 = func('汪某'); setTimeout(f1, 1000)//汪某
在ES5.1里面函数是这样执行的(不讨论使用严格和一些特殊状况,JS好复杂的),按以下顺序执行:nginx
1. 肯定“this”的值 (确切的来讲,this在JS里面不是一个变量名而是一个关键字) 2. 建立一个新的做用域 3. 处理形参/实参(没有定义过才声明,不管如何都从新赋值,没有对应实参则赋值为"undefined"): 对于每个传入的实参,按照从左往右的顺序依次执行:若是对应的形参在本做用域中尚未定义,则在本做用域中声明形参,并赋值。若是已经定义过了,则从新给其赋值。(没有对应实参则赋值为"undefined")(没有定义:就是“没有声明”的意思) 4. 处理函数定义(没有定义过才声明,不管如何都从新赋值): 对该函数中全部的定义的函数,按照代码写的顺序依次执行:若是这个变量名在本做用域中尚未定义,则在本做用域中声明这个函数名,而且赋值为对应的函数,若是定义了这个变量,在可写的状况下从新给这个变量赋值为这个函数,不然抛出异常。 5. 处理 "arguments"(没有定义过才声明和赋值): 若是在本做用域中没有定义 arguments,则在本做用域中声明arguments并给其赋值。 6. 处理变量声明(没有定义过才声明,不赋值): 对于全部变量声明,按照代码写的顺序依次执行:若是在本做用域中没有定义这个变量,则在本做用域中声明这个变量,赋值为undefined 7. 而后执行函数代码。(固然是去变量定义里面的 var 执行)
1. 建立空对象; var obj = {}; 2. 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象; obj.__proto__ = ClassA.prototype; 3. 使用新对象调用函数,函数中的this被指向新实例对象: ClassA.call(obj);//{}.构造函数(); 4. 若是无返回值或者返回一个非对象值,则将新对象返回;若是返回值是一个新对象的话那么直接直接返回该对象。
综合应用场景面试
防抖函数分为非当即执行版和当即执行版。算法
/** * @desc 函数防抖 * @param func 函数 * @param wait 延迟执行毫秒数 * @param immediate true 表当即执行,false 表非当即执行 */ function debounce(func,wait,immediate) { let timeout; return function () { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait) if (callNow) func.apply(context, args) } else { timeout = setTimeout(function(){ func.apply(context, args) }, wait); } } }
所谓节流,就是指连续触发事件可是在n秒中只执行一次函数。节流会稀释函数的执行频率。
对于节流,通常有两种方式能够实现,分别是时间戳版和定时器版。
/** * @desc 函数节流 * @param func 函数 * @param wait 延迟执行毫秒数 * @param type 1 表时间戳版,2 表定时器版 */ function throttle(func, wait ,type) { if(type===1){ var previous = 0; }else if(type===2){ var timeout; } return function() { let context = this; let args = arguments; if(type===1){ let now = Date.now(); if (now - previous > wait) { func.apply(context, args); previous = now; } }else if(type===2){ if (!timeout) { timeout = setTimeout(() => { timeout = null; func.apply(context, args) }, wait) } } } }
改变原数组的方法
语法:arrayObject.splice(index,howmany,item1,.....,itemX) 参数: 1.index:必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。 2.howmany:可选。要删除的项目数量。若是设置为 0,则不会删除项目。 3.item1, ..., itemX: 可选。向数组添加的新项目。 返回值: 若是有元素被删除,返回包含被删除项目的新数组。
语法:arrayObject.sort(sortby) 参数: 1.sortby 可选。规定排序顺序。必须是函数。。 返回值: 返回包排序后的新数组。
语法:arrayObject.pop() 参数:无 返回值: 返回被删除的元素。
语法:arrayObject.shift() 参数:无 返回值: 返回被删除的元素。
语法:arrayObject.push(newelement1,newelement2,....,newelementX) 参数: 1.newelement1 必需。要添加到数组的第一个元素。 2.newelement2 可选。要添加到数组的第二个元素。 3.newelementX 可选。可添加若干个元素。 返回值: arrayObject 的新长度。
语法:arrayObject.unshift(newelement1,newelement2,....,newelementX) 参数: 1.newelement1 必需。要添加到数组的第一个元素。 2.newelement2 可选。要添加到数组的第二个元素。 3.newelementX 可选。可添加若干个元素。 返回值: arrayObject 的新长度。
语法:arrayObject.reverse() 参数:无 返回值: 颠倒后的新数组。
语法: array.copyWithin(target, start = 0, end = this.length) 参数: 1.target(必需):从该位置开始替换数据。若是为负值,表示倒数。 2.start(可选):从该位置开始读取数据,默认为 0。若是为负值,表示倒数。 3.end(可选):到该位置前中止读取数据,默认等于数组长度。若是为负值,表示倒数。 返回值: 返回当前数组。
语法: array.fill(value, start, end) 参数: 1.value 必需。填充的值。 2.start 可选。开始填充位置。 3.end 可选。中止填充位置 (默认为 array.length) 返回值: 返回当前数组。
不改变原数组的方法
语法: array.slice(begin, end); 参数: 1.begin(可选): 索引数值,接受负值,从该索引处开始提取原数组中的元素,默认值为0。 2.end(可选):索引数值(不包括),接受负值,在该索引处前结束提取原数组元素,默认值为数组末尾(包括最后一个元素)。 返回值: 返回一个从开始到结束(不包括结束)选择的数组的一部分浅拷贝到一个新数组对象,且原数组不会被修改。
语法:array.join(str) 参数: 1.str(可选): 指定要使用的分隔符,默认使用逗号做为分隔符。 返回值: 返回生成的字符串。
语法: var newArr =oldArray.concat(arrayX,arrayX,......,arrayX) 参数: 1.arrayX(必须):该参数能够是具体的值,也能够是数组对象。能够是任意多个。 返回值: 返回返回合并后的新数组。
语法:array.indexOf(searchElement,fromIndex) 参数: 1.searchElement(必须):被查找的元素 2.fromIndex(可选):开始查找的位置(不能大于等于数组的长度,返回-1),接受负值,默认值为0。 返回值: 返回下标
语法:arr.lastIndexOf(searchElement,fromIndex) 参数: 1.searchElement(必须): 被查找的元素 2.fromIndex(可选): 逆向查找开始位置,默认值数组的长度-1,即查找整个数组。 返回值: 方法返回指定元素,在数组中的最后一个的索引,若是不存在则返回 -1。(从数组后面往前查找)
语法: array.includes(searchElement,fromIndex=0) 参数: 1.searchElement(必须):被查找的元素 2.fromIndex(可选):默认值为0,参数表示搜索的起始位置,接受负值。正值超过数组长度,数组不会被搜索,返回false。负值绝对值超过长数组度,重置从0开始搜索。 返回值: 返回布尔
声明一个匿名函数,立刻调用这个匿名函数。目的是保护内部变量不受污染。
(function(n1, n2) { console.log("这是匿名函数的自执行的第一种写法,结果为:" + (n1 + n2)) })(10, 100); (function start(n1, n2) { console.log("这是函数声明方式的自执行的第一种写法,结果为:" + (n1 + n2)) })(10, 100); (function(n1, n2) { console.log("这是匿名函数的自执行的第二种写法,结果为:" + (n1 + n2)) }(10, 100)); (function start(n1, n2) { console.log("这是函数声明方式的自执行的第二种写法,结果为:" + (n1 + n2)) }(10, 100));
每一个对象都会在其内部初始化一个属性,就是原型(原型),当咱们访问一个对象的属性时,若是这个对象内部不存在这个属性,那么他就会去原型里找这个属性,这个原型又会有本身的原型,因而就这样一直找下去,也就是咱们平时所说的原型链的概念。
关系:instance.constructor.prototype = instance。原
特色:JavaScript的对象是经过引用来传递的,咱们建立的每一个新对象实体中并无一份属于本身的原型副本,当咱们修改原型时,相关与之对象的继承也会改变这一
当咱们须要一个属性时,JavaScript的引擎会先看当前对象中是否有这个属性,若是没有的话,就会查找它的原型对象是否有这个属性,如此递推下去,一致检索到的对象内建对象。
function Func(){} Func.prototype.name = "汪某"; Func.prototype.getInfo = function() { return this.name; } var person = new Func(); console.log(person.getInfo());//"汪某" console.log(Func.prototype);//Func { name = "汪某", getInfo = function() }
参考:js原型和原型链
一句话归纳无极:无极对象用于异步操做,它表示一个还没有完成且预计在将来完成的异步操做。
承诺是用来解决两个问题的:
这个承诺能够解决异步的问题,自己不能说的承诺是异步的
/*Promise 的简单实现*/ class MyPromise { constructor(fn) { this.resolvedCallbacks = []; this.rejectedCallbacks = []; this.state = "PADDING"; this.value = ""; fn(this.resolve.bind(this), this.reject.bind(this)); } resolve(value) { if (this.state === "PADDING") { this.state = "RESOLVED"; this.value = value; this.resolvedCallbacks.forEach(cb => cb()); } } reject(value) { if (this.state === "PADDING") { this.state = "REJECTED"; this.value = value; this.rejectedCallbacks.forEach(cb => cb()); } } then(resolve = function() {}, reject = function() {}) { if (this.state === "PADDING") { this.resolvedCallbacks.push(resolve); this.rejectedCallbacks.push(reject); } if (this.state === "RESOLVED") { resolve(this.value); } if (this.state === "REJECTED") { reject(this.value); } } }
如何使用Async函数
async function timeout(ms) { await new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); } asyncPrint('hello world', 50);
上面代码指定50毫秒之后,输出hello world。进一步说,async函数彻底能够看做多个异步操做,包装成的一个Promise对象,而等待命令就是内部而后命令的语法糖。
待补充......
浅拷贝和深拷贝都只针对于引用数据类型,浅拷贝只复制指向某个对象的指针,而不复制对象自己,新旧对象仍是共享同一块内存;但深拷贝会另外创造一个如出一辙的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
区别:浅拷贝只复制对象的第一层属性,深拷贝能够对对象的属性进行递归复制;
function simpleCopy (initalObj) { var obj = {}; for ( var i in initalObj) { obj[i] = initalObj[i]; } return obj; }
let newObj = Object.assign({}, obj);
let newObj = {...obj};
深拷贝的实现方式
用JSON.stringify把对象转换成字符串,再用JSON.parse把字符串转换成新的对象。
let newObj = JSON.parse(JSON.stringify(obj));
用lodash函数库提供的_.cloneDeep方法实现深拷贝。
var _ = require('lodash'); var newObj = _.cloneDeep(obj);
function deepClone(obj) { let objClone = Array.isArray(obj) ? [] : {}; if (obj && typeof obj === "object") { // for...in 会把继承的属性一块儿遍历 for (let key in obj) { // 判断是否是自有属性,而不是继承属性 if (obj.hasOwnProperty(key)) { //判断ojb子元素是否为对象或数组,若是是,递归复制 if (obj[key] && typeof obj[key] === "object") { objClone[key] = this.deepClone(obj[key]); } else { //若是不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; }
跨域须要针对浏览器的同源策略来理解,同源策略指的是请求必须是同一个端口,同一个协议,同一个域名,不一样源的客户端脚本在没有明确受权的状况下,不能读写对方资源。
受浏览器同源策略的影响,不是同源的脚本不能操做其余源下面的对象。想要操做另外一个源下的对象是就须要跨域。
1.通常用于遍历对象的可枚举属性。以及对象从构造函数原型中继承的属性。对于每一个不一样的属性,语句都会被执行。 2.不建议使用for in 遍历数组,由于输出的顺序是不固定的。 3.若是迭代的对象的变量值是null或者undefined, for in不执行循环体,建议在使用for in循环以前,先检查该对象的值是否是null或者undefined
1.for…of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上建立一个迭代循环,调用自定义迭代钩子,并为每一个不一样属性的值执行语句
遍历对象
var s = { a: 1, b: 2, c: 3 } var s1 = Object.create(s); for (var prop in s1) { console.log(prop); //a b c console.log(s1[prop]); //1 2 3 } for (let prop of s1) { console.log(prop); //报错以下 Uncaught TypeError: s1 is not iterable } for (let prop of Object.keys(s1)) { console.log(prop); // a b c console.log(s1[prop]); //1 2 3 }
冒泡型事件:事件按照从最特定的事件目标到最不特定的事件目标(文件对象)的顺序触发。
w3c的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true。
//阻止冒泡行为 function stopBubble(e) { //若是提供了事件对象,则这是一个非IE浏览器 if ( e && e.stopPropagation ) //所以它支持W3C的stopPropagation()方法 e.stopPropagation(); else //不然,咱们须要使用IE的方式来取消事件冒泡 window.event.cancelBubble = true; }
w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false
//阻止浏览器的默认行为 function stopDefault( e ) { //阻止默认浏览器动做(W3C) if ( e && e.preventDefault ) e.preventDefault(); //IE中阻止函数器默认动做的方式 else window.event.returnValue = false; return false; }
//变量提高 console.log(a); // undefined console.log(b); // 报错 console.log(c); // 报错 var a = 1; let b = 2; const c = 3; // 全局声明 console.log(window.a) // 1 // 重复声明 let b = 200;//报错
其实这里很容易理解,var是能够变量提高的。而让和const是必须声明后才能调用的。对于let和const来讲,这里就是暂缓性死区。
ES6新增的类其实也是语法糖,JS底层其实没有类的概念的,其实也是原型继承的封装。
class People { constructor(props) { this.props = props; this.name = '汪某'; } callMyName() { console.log(this.name); } } class Name extends People { // extends 其实就是继承了哪一个类 constructor(props) { // super至关于 把类的原型拿过来 // People.call(this, props) super(props) } callMyApple() { console.log('我是汪某!') } } let a = new Name('啊啊啊') a.callMyName(); //汪某 a.callMyApple(); // 我是汪某!
<font color = red>设置</ font>数据结构相似数组,但全部成员的值惟一。
let a = new Set(); [1,2,2,1,3,4,5,4,5].forEach(x=>a.add(x)); for(let k of a){ console.log(k) }; // 1 2 3 4 5
基本使用
let a = new Set([1,2,3,3,4]); [...a]; // [1,2,3,4] a.size; // 4 // 数组去重 [...new Set([1,2,3,4,4,4])];// [1,2,3,4]
方法
let a = new Set(); a.add(1).add(2); // a => Set(2) {1, 2} a.has(2); // true a.has(3); // false a.delete(2); // true a => Set(1) {1} a.clear(); // a => Set(0) {}
<font color = red> Map </ font>结构提供了“值 - 值”的对应,是一种更完善的Hash结构实现。
let a = new Map(); let b = {name: 'leo' }; a.set(b,'my name'); // 添加值 a.get(b); // 获取值 a.size; // 获取总数 a.has(b); // 查询是否存在 a.delete(b); // 删除一个值 a.clear(); // 清空全部成员 无返回
基本使用
let a = new Map([ ['name','wzx'], ['age',23] ])
let a = new Map(); a.set(1,'aaa').set(1,'bbb'); a.get(1); // 'bbb'
new Map().get('asdsad'); // undefined
let a = new Map(); let a1 = ['aaa']; let a2 = ['aaa']; a.set(a1,111).set(a2,222); a.get(a1); // 111 a.get(a2); // 222
方法
let a = new Map([ ['name', 'leo'], ['age', 18] ]) for (let i of a.keys()) { console.log(i) }; //name //age for (let i of a.values()) { console.log(i) }; //leo //18 for (let i of a.entries()) { console.log(i) }; //["name", "leo"] a.forEach((v, k, m) => { console.log(`key:${k},value:${v},map:${m}`) }) //["age", 18]
function New(func) { var res = {}; if (func.prototype !== null) { res.__proto__ = func.prototype; } var ret = func.apply(res, Array.prototype.slice.call(arguments, 1)); if ((typeof ret === "object" || typeof ret === "function") && ret !== null) { return; ret; } return; res; } var obj = New(A, 1, 2); // equals to var obj = new A(1, 2);
Function.prototype.call2 = function (context) { var context = context || window; context.fn = this; var args = []; for(var i = 1, len = arguments.length; i < len; i++) { args.push('arguments[' + i + ']'); } var result = eval('context.fn(' + args +')'); delete context.fn return result; }
Function.prototype.apply2 = function (context, arr) { var context = Object(context) || window; context.fn = this; var result; if (!arr) { result = context.fn(); } else { var args = []; for (var i = 0, len = arr.length; i < len; i++) { args.push('arr[' + i + ']'); } result = eval('context.fn(' + args + ')') } delete context.fn return result; }
Function.prototype.bind2 = function (context) { if (typeof this !== "function") { throw new Error("Function.prototype.bind - what is trying to be bound is not callable"); } var self = this; var args = Array.prototype.slice.call(arguments, 1); var fNOP = function () {}; var fbound = function () { self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments))); } fNOP.prototype = this.prototype; fbound.prototype = new fNOP(); return fbound; }
function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log('parent name:', this.name); } function Child(name, parentName) { Parent.call(this, parentName); this.name = name; } function create(proto) { function F() {} F.prototype = proto; return new F(); } Child.prototype = create(Parent.prototype); Child.prototype.sayName = function() { console.log('child name:', this.name); } Child.prototype.constructor = Child; var parent = new Parent('汪某'); parent.sayName();// parent name: 汪某 var child = new Child('son', '汪某');
面试够用版
function myPromise(constructor) { let self = this; self.status = "pending" //定义状态改变前的初始状态 self.value = undefined; //定义状态为resolved的时候的状态 self.reason = undefined; //定义状态为rejected的时候的状态 function resolve(value) { //两个==="pending",保证了状态的改变是不可逆的 if (self.status === "pending") { self.value = value; self.status = "resolved"; } } function reject(reason) { //两个==="pending",保证了状态的改变是不可逆的 if (self.status === "pending") { self.reason = reason; self.status = "rejected"; } } //捕获构造异常 try { constructor(resolve, reject); } catch (e) { reject(e); } } //同时,须要在 myPromise的原型上定义链式调用的 then方法: myPromise.prototype.then = function(onFullfilled, onRejected) { let self = this; switch (self.status) { case "resolved": onFullfilled(self.value); break; case "rejected": onRejected(self.reason); break; default: } } //测试一下: var p = new myPromise(function(resolve, reject) { resolve(1) }); p.then(function(x) { console.log(x) })
高级版请参考:史上最最最详细的手写承诺教程
完整版详见上方,此处给出面试版
// 防抖函数 function debounce(fn, wait) { let timer; return function() { if (timer) clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, arguments) }, wait) } }
// 节流函数 function throttle(fn, wait) { let prev = new Date(); return function() { const args = arguments; const now = new Date(); if (now - prev > wait) { fn.apply(this, args); prev = new Date(); } } }
面试版
function deepCopy(obj) { //判断是不是简单数据类型, if (typeof obj == "object") { //复杂数据类型 var result = obj.constructor == Array ? [] : {}; for (let i in obj) { result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i]; } } else { //简单数据类型 直接 == 赋值 var result = obj; } return result; }
vue.js是采用数据劫持结合发布者 - 订阅者模式的方式,经过Object.defineProperty()来劫持各个属性的setter,getter,在数据变更时发布消息给订阅者,触发相应的监听回调。
//vue实现数据双向绑定的原理就是用Object.defineproperty()从新定义(set方法)对象设置属性值和(get方法)获取属性值的操纵来实现的。
//Object.property()方法的解释:Object.property(参数1,参数2,参数3) 返回值为该对象obj
//其中参数1为该对象(obj),参数2为要定义或修改的对象的属性名,参数3为属性描述符,属性描述符是一个对象,主要有两种形式:数据描述符和存取描述符。这两种对象只能选择一种使用,不能混合使用。而get和set属于存取描述符对象的属性。
//这个方法会直接在一个对象上定义一个新属性或者修改对象上的现有属性,并返回该对象。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <div id="myapp"> <input v-model="message" /><br> <span v-bind="message"></span> </div> <script type="text/javascript"> var model = { message: "" }; var models = myapp.querySelectorAll("[v-model=message]"); for (var i = 0; i < models.length; i++) { models[i].onkeyup = function() { model[this.getAttribute("v-model")] = this.value; } } // 观察者模式 / 钩子函数 // defineProperty 来定义一个对象的某个属性 Object.defineProperty(model, "message", { set: function(newValue) { var binds = myapp.querySelectorAll("[v-bind=message]"); for (var i = 0; i < binds.length; i++) { binds[i].innerHTML = newValue; }; var models = myapp.querySelectorAll("[v-model=message]"); for (var i = 0; i < models.length; i++) { models[i].value = newValue; }; this.value = newValue; }, get: function() { return this.value; } }) </script> </body> </html>
Vue3.0将用原生代理替换Object.defineProperty
为何要替换Object.defineProperty?
什么是代理
总共分为8个阶段建立前/后,载入前/后,更新前/后,销毁前/后
说一下每个阶段能够作的事情
附上一张中文解析图
在路由器目录下的index.js文件中,对路径属性加上/:id。
使用路由器对象的params.id获取
三种
是一个能方便vue实例及其组件传输数据的插件方便传输数据,做为公共存储数据的一个库
state:状态中心
突变:更改状态,同步的
动做:异步更改状态
getters:获取状态
modules:将州分红多个模块,便于管理
应用场景:单页应用中,组件之间的状态音乐播放,登陆状态,加入购物车。
网上找的一个通俗易懂的了解vuex的例子
公司有个仓库
1.State(公司的仓库)
2.Getter(只能取出物品,包装一下,不能改变物品任何属性)
3.Muitation(仓库管理员,只有他能够直接存储到仓库)
4.Action(公司的物料采购员,负责从外面买东西和接货,要往仓库存东西,告诉仓库管理员要存什么)
很是要注意的地方:只要刷新或者退出浏览器,仓库清空。
哈希模式URL里面永远带着#号,咱们在开发当中默认使用这个模式。那么何时要用历史的模式呢?若是用户考虑网址的规范那么就须要使用历史模式,由于历史模式没有#号,是个正常的URL适合推广宣传。固然其功能也有区别,好比咱们在开发应用程序的时候有分享页面,那么这个分享出去的页面就是用VUE或是反应作的,我们把这个页面分享到第三方的应用程序里,有的应用程序里面的网址是不容许带有#号的,因此要将#号去除那么就要使用历史模式,可是使用的历史模式还有一个问题就是,在访问二级页面的时候,作刷新操做,会出现404错误,那么就须要和后端人配合让他配置一下apache的或是nginx的的URL重定向,重定向到你的首页路由上就OK啦。
router有两种模式:hash模式(默认),history模式(需配置模式:'history')
| 哈希| 历史
- | - | -
url显示| 有#,很低| 无#,好看|
回车刷新| 能够加载到hash值对应页面| 通常就是404掉了|
支持版本| 支持低版本浏览器和IE浏览器| 支持低版本浏览器和IE浏览器|
参考:详解VUE的差别算法
当咱们在浏览器中输入一个URL,例如“ www.google.com ”时,这个地址并非谷歌网站真正意义上的地址。互联网上每一台计算机的惟一标识是它的IP地址,所以咱们输入的网址首先须要先解析为IP地址,这一过程叫作DNS解析。
DNS解析是一个递归查询的过程。例如,咱们须要解析“ www.google.com ”时,会经历如下步骤:
HTTP协议是使用TCP协议做为其传输层协议的,在拿到服务器的IP地址后,浏览器客户端会与服务器创建TCP链接该过程包括三次握手:
三次握手主要是为了防止已经失效的请求报文字段发送给服务器,浪费资源。
客户端与服务器四次挥手,断开TCP链接。