1.const p = Promise.reject(‘出错了’);
// 等同于
const p = new Promise((resolve, reject) => reject(‘出错了’))
then后会执行第二个函数。
如果在then的第一个函数里抛出了异常,后面的catch能捕获到,而then的第二个函数捕获不到
Promise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数。
2.vue-router的hash模式原理是onhashchange事件,hostory是pushstate方法
3.模块化最初:
(1)函数包裹
(2)对象
(3)闭包
之后出现commonjs用在服务端,一个页面就是一个模块。
4.require,exports,module.export属于AMD规范,import,export,export default属于ES6规范,seajs和node.js都是cmd,seajs导入导出(define,module.exports,require)
5.vue中子组件不能直接修改父组件传来的值,可以使用事件通知父组件自己修改,简单写法.sync
6.
console.log(11111);
setTimeout(() => {
console.log("timeout")
}, 0)
new Promise((resolve) => {
console.log(22222)
resolve();
}).then(() => {
console.log(3333)
return new Promise((resolve) => {
console.log(4444)
resolve();
});
}).then(()=>{
console.log(5555)
})
先执行主函数,在执行then再执行settimeout
7.浏览器无法识别模块化代码,babel可以把es6的代码转为commonjs,但是只能在node坏境下执行,所以用webpack打包
8.为什么取消了浏览器环境并改为双线程模型?
基于web技术来渲染小程序有很多不可控的因素和安全风险,这是因为web技术太开放灵活,可以通过js来跳转或任意修改页面上的内容
小程序是经过原生的webview来渲染
9.小程序可以在本地编译也可以上传到服务器进行编译。
10.小程序的运行环境分为2部分:逻辑层和视图层。其中逻辑层是加载小程序应用的JS脚本,负责处理业务逻辑的。而视图层负责渲染TTML模板和TTSS样式,显示页面。
小程序的逻辑层和视图层是2个独立的线程来管理。逻辑层的线程启动JSCore引擎去执行JS脚本,处理业务逻辑。视图层的每个页面使用一个Webview进行渲染,多个页面则是多个Webview。 所以一个小程序应用只有一个JSCore线程,多个Webview线程。
11.飞书小程序纪要:
(1)当小程序启动之后,会触发 app.js 里定义的onLaunch方法
(2)小程序会有两种情况,一种是冷启动,一种是热启动。冷启动就是每次都需要重新加载启动,而热启动则是将后台状态切换到前台状态
小程序销毁机制:
移动端:
通常,只有当小程序进入后台一定时间,或者系统资源占用过高,才会被销毁
pc端:
PC端只要小程序没有关闭,小程序会一直处于运行状态,如果关闭了,会直接销毁。
热启动较复杂,因为可能会自动产生一些跳转.
可以配置不同模式下指定不同的启动页面
12.js中在for循环里使用splice会出现像java里快速失败的问题,splice改变了原来数组的长度,导致删除不符合逾期
13.vue for 循环中使用 await
async tidyData(){
item.categorys.forEach(async item2 => {
let customModelList = await this.tidyDataCustom(item2)
})
}
14.原本异步任务中修改数值,下面的同步代码是不能读取到的,但vue中绑定到data中就可以读取到
15,.await和async是把当前对应的函数内转化为同步执行
16.for of不能遍历数组,for in遍历对象获取的是key,遍历数组获取的是索引
17.用typeof方法只能初步判断number string undefined boolean object function symbol这几种初步类型
使用Object.prototype.toString.call(obj).slice(8, -1) === 'Date’能判断具体的类型数组,函数
18.promise的.then反回的是新的promise但是不会返回参数,需要自己返回
await后面接一个会return new promise的函数并执行它
async函数返回一个promise对象,await接收的是promise里的res参数,如果没有接收到,await下面的代码不会执行
19.vue中如果修改一个对象中没有定义的属性,页面不会刷新,但是如果直接修改这个对象就会刷新。但是初始化后for循环往里加值是不会刷新的
20.es6的map中的键可以是任意值
21.标准盒子模型是边框会撑开盒子,content-box(标准盒子模型width不包括padding和border)border-box(相反)
22.catch是then第二个参数的语法糖
23.直接给对象赋值的是静态方法,给原型加方法是实例方法
24…native - 主要是给自定义的组件添加原生事件,可以理解为该修饰符的作用就是把一个vue组件转化为一个普通的HTML标签,并且该修饰符对普通HTML标签是没有任何作用的。
25.vue的事件总线,同一个vue实例里通过
e
m
i
t
发
出
事
件
,
通
过
emit发出事件,通过
emit发出事件,通过on接收,实现通信
26.vue的事件默认是冒泡触发
27.重排时一定会发生重绘,当文档流里的元素没有发生位置上的改变时,只会发生重绘
28.每个宏任务结束后都会清空微任务
29.track-by属性:数据修改时,数据不改变的dom不会被重新渲染,已经改变的数据所在的dom才会被重新渲染
30.getBoundingClientRect返回这个元素视窗距离的集合
31.不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据。
32.当A->B->C时,B里面没有使用到A里的属性时,可通过v-bind="
a
t
t
r
s
"
把
不
需
要
的
属
性
传
给
C
属
性
,
attrs"把不需要的属性传给C属性,
attrs"把不需要的属性传给C属性,listeners则是传事件
33.有时offsetHeight会返回零,因为您拥有的元素创建的图像尚未在Dom中呈现
34.在有滚动条的页面中,absolute会跟随页面滑动,fixed不会滑动,始终固定在同一位置
35.function (e) {
//现代浏览器阻止默认事件
if (e && e.preventDefault) e.preventDefault();
//IE阻止默认事件
else window.event.returnValue = false;
return false;
};可以让当前点击去阻止该页面所有默认事件
36.组件绑定事件时
- 普通组件绑定事件不能添加.native, 添加后事件失效
- 自定义组件绑定事件需要添加.native, 否则事件无效
37.document.defaultView.getComputedStyle(el),这个方法可以获取元素的样式,不局限写在行内的style
关于vue框架样式的笔记:
1.不写scoped,会成为全局样式,前面增加class可以消除全局污染,但是如果框架上已经封装了一层,加class就会因为css的加载顺序出现不同的效果(因为同级别)
2.加上scoped,会为每个class加个唯一的标识符,生成出来的dom和css都会有标识符,但是dom上的标识符只会在子组件的最外层,所以我们写的样式无法命中子组件也就无法修改其样式,我们可以使用/deep/后面跟子组件的样式,不生成其标识符,用来修改子组件样式。
关于java,js的参数传递:
var s = 2;
function a(b){
b = 3 ;
}
a(s)
console.log(s); //2
var s = {a:2};
function a(b){
b.a = 3 ;
}
a(s)
console.log(s); //{a:3}
var s = {a:2};
function a(b){
b = {a:3} ;
}
a(s)
console.log(s); //{a:2}
var s = {a:2};
function a(){
s.a = 3;
}
a(s)
console.log(s); //{a:3}
var s = {a:2};
function a(){
s = { a:3 };
}
a(s)
console.log(s); //{a:3}
// 综上所述,js和java是共享传递,会在参数参值时生成一个副本
38.双向绑定
一.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" id="inputText" oninput="input(event)">
<span id="spanText"></span>
<button onclick="buttonClick()">增加</button>
</body>
<script>
var inputText = document.getElementById('inputText');
var spanText = document.getElementById('spanText');
/*
vue中的data
*/
var data = {
value: 0
}
var _data = JSON.parse(JSON.stringify(data));
Object.defineProperty(data, "value", {
set(newValue,oldValue) {
inputText.value = newValue;
spanText.innerHTML = newValue;
_data.value = newValue;
},
get(){
return _data.value
}
})
/*
用户操作
*/
function buttonClick() {
data.value += 1;
};
function input(e){
data.value = e.target.value;
}
</script>
</html>
vue进行编译时,就是将挂载目标的所有子节点劫持到DocumentFragment中,经过一番处理之后,再将DocumentFragment整体返回插入挂载目标
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"><input type="text" id="a"><span id="b">44451323</span></div>
</body>
<script>
// 摘取app节点下的所有子节点进dom文档对象,然后重新挂载
var dom = nodeToFragment(document.getElementById('app'));
// console.log(document.getElementById('app').childNodes);
function nodeToFragment(node) {
var flag = document.createDocumentFragment();
var child;
// firstChild适用于IE8以下,并且标签中有空格时会有text节点对象
while (child = node.firstChild) {
// appendChil会把原来页面的元素剪切然后增加到所在的节点后
flag.appendChild(child);
}
return flag;
}
document.getElementById('app').appendChild(dom);
</script>
</html>
创建从data层到view层
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text">
{{ text }}
</div>
</body>
<script>
// 定义一个编译方法,在最后时通过传入的节点,去vm搜索对应的值替换
function compile(node, vm) {
// 确定正则
var reg = /\{\{(.*)\}\}/;
// 节点类型为元素
if (node.nodeType === 1) {
// 获取所有属性
var attr = node.attributes;
for (const key in attr) {
var element = attr[key];
// 如果属性有v-model
if (element.nodeName === 'v-model') {
// 获取v-model绑定的属性值
var value = element.nodeValue;
// 把vm里data的value值给当前节点的vlaue
node.value = vm.data[value]
}
}
}
// 当前节点为text
if (node.nodeType === 3) {
// 检测是否符合正则
if (reg.test(node.nodeValue)) {
// 检测到后会自动封装到RegExp对象
var name = RegExp.$1;
name = name.trim();
// 去vm里取对应的值并修改
node.nodeValue = vm.data[name];
}
}
}
// 把真实dom劫持到文档片段中,同时会把每个节点都编译
function nodeToFragment(node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
// 每层节点都会进行编译
compile(child, vm);
// 把编译后的节点放入文档片段里
flag.appendChild(child);
}
return flag;
}
// 定义vue构造函数
function Vue(options) {
this.data = options.data;
var id = options.el;
// 传入真实dom,处理完后返回
var dom = nodeToFragment(document.getElementById(id), this);
// 最后替换app里的内容
document.getElementById(id).appendChild(dom);
console.log('123', document.getElementById(id));
}
var vm = Vue({
el: 'app',
data: {
text: 'hello world'
}
})
var s = 1;
function a(s){
s= 2;
}
a(s)
console.log('s',s);
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text" oninput="input(event)">
{{ text }}
</div>
</body>
<script>
function input(event){
console.log('event',event.target.value);
vm.data.text = event.target.value
}
// 定义一个编译方法,在最后时通过传入的节点,去vm搜索对应的值替换
function compile(node, vm) {
// 确定正则
var reg = /\{\{(.*)\}\}/;
// 节点类型为元素
if (node.nodeType === 1) {
// 获取所有属性
var attr = node.attributes;
for (const key in attr) {
var element = attr[key];
// 如果属性有v-model
if (element.nodeName === 'v-model') {
// 获取v-model绑定的属性值
var value = element.nodeValue;
// 把vm里data的value值给当前节点的vlaue
node.value = vm.data[value]
}
}
}
// 当前节点为text
if (node.nodeType === 3) {
// 检测是否符合正则
if (reg.test(node.nodeValue)) {
// 检测到后会自动封装到RegExp对象
var name = RegExp.$1;
name = name.trim();
// 去vm里取对应的值并修改
node.nodeValue = vm.data[name];
}
}
}
// 把真实dom劫持到文档片段中,同时会把每个节点都编译
function nodeToFragment(node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
// 每层节点都会进行编译
compile(child, vm);
// 把编译后的节点放入文档片段里
flag.appendChild(child);
}
return flag;
}
// 定义vue构造函数
function Vue(options) {
this.data = options.data;
observe(this.data, this);
var id = options.el;
// 传入真实dom,处理完后返回
var dom = nodeToFragment(document.getElementById(id), this);
// 最后替换app里的内容
document.getElementById(id).appendChild(dom);
}
function defineReactive(obj, key, val) {
console.log(obj,key,val);
// 响应式的数据绑定
Object.defineProperty(obj, key, {
get: function () {
return val;
},
set: function (newVal) {
if (newVal === val) {
return;
} else {
val = newVal;
console.log(123451,val); // 观察者模式分发,去通知页面上所有绑定的值
}
}
});
}
function observe(obj, vm) {
Object.keys(obj).forEach(function (key) {
defineReactive(obj, key, obj[key]);
});
}
var vm = new Vue({
el: 'app',
data: {
text: 'hello world'
}
})
</script>
</html>
上一步已经实现了给data里每一个键都绑定了监听,接下来需要做的是更新页面上所有的表达式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
<script>
// 定义个主题对象
function Dep() {
// 包含的观察者
this.subs = [];
// 唤醒观察者里的方法
this.notify = function () {
this.subs.forEach(sub => {
// 调用观察者里的方法
sub.update();
})
}
// 注册观察者方法
this.addSubs = function(sub){
this.subs.push(sub)
}
}
// 观察者
var sub1 = {
update: function () {
console.log(1);
}
}
var sub2 = {
update: function () {
console.log(2);
}
}
var sub3 = {
update: function () {
console.log(3);
}
}
// 注册观察者
var s = [sub1,sub2,sub3];
var dep = new Dep();
s.forEach(sub=>{
dep.addSubs(sub)
})
// 当数据有变化时,就会通知所有观察者更新,之后问题就是如何收集到所有的观察者并更新
dep.notify();
</script>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>forvue</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text">
{{ text }}
</div>
<script>
function compile(node, vm) {
var reg = /\{\{(.*)\}\}/;
// 节点类型为元素
if (node.nodeType === 1) {
var attr = node.attributes;
// 解析属性
for (var i = 0; i < attr.length; i++) {
if (attr[i].nodeName == 'v-model') {
var name = attr[i].nodeValue; // 获取v-model绑定的属性名
node.addEventListener('input', function (e) {
// 给相应的data属性赋值,进而触发属性的set方法
vm.data[name] = e.target.value;
})
node.value = vm.data[name]; // 将data的值赋值给该node
node.removeAttribute('v-model');
}
}
}
// 节点类型为text
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1; // 获取匹配到的字符串
name = name.trim();
// node.nodeValue = vm.data[name]; // 将data的值赋值给该node
// 如果符合差值表达式的类型,就会生成一个观察者的类
new Watcher(vm, name, node);
}
}
}
// 观察者类
function Watcher(vm, name, node) {
Dep.target = this;
// 观察者的名字
this.name = name;
// 观察者节点类型
this.node = node;
this.vm = vm;
this.update = function () {
this.get();
this.node.nodeValue = this.value;
}
this.get = function () {
this.value = this.vm.data[this.name];
}
this.update();
Dep.target = null;
};
// 主题类
function Dep() {
// 所有的观察者
this.subs = [];
// 增加观察者方法
this.addSub = function (sub) {
this.subs.push(sub)
}
this.notify = function (params) {
this.subs.forEach(sub => {
sub.update()
})
}
}
function nodeToFragment(node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
compile(child, vm);
flag.appendChild(child); // 将子节点劫持到文档片段中
}
return flag;
}
function Vue(options) {
this.data = options.data;
var data = this.data;
observe(data, this);
var id = options.el;
var dom = nodeToFragment(document.getElementById(id), this);
// 编译完成后,将dom返回到app中。
document.getElementById(id).appendChild(dom);
}
var vm = new Vue({
el: 'app',
data: {
text: 'hello world'
}
});
function defineReactive(obj, key, val) {
console.log(obj, key, val);
// 每个属性都会去设置一个主题类
var dep = new Dep();
// 响应式的数据绑定
Object.defineProperty(obj, key, {
get: function () {
if (Dep.target) {
dep.addSub(Dep.target);
}
return val;
},
set: function (newVal) {
if (newVal === val) {
return;
} else {
val = newVal;
console.log(123, val); // 去通知所有依赖更新
// 方法一:遍历页面上所有节点,找到命中的key,更新
// 更新时会去通知所有观察者更新
dep.notify()
}
}
});
}
function observe(obj, vm) {
Object.keys(obj).forEach(function (key) {
defineReactive(obj, key, obj[key]);
});
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" v-model="text">
{{ text }}
<button onclick="buttonClick()">{{text}}</button>
<span>{{ text }}</span>
</div>
</body>
<script>
// 点击修改方法
function buttonClick() {
console.log('123');
vm.data.text += 1
}
// 定义一个编译方法,在最后时通过传入的节点,去vm搜索对应的值替换
function compile(node, vm) {
// 确定正则
var reg = /\{\{(.*)\}\}/;
// 节点类型为元素
if (node.nodeType === 1) {
// 获取所有属性
var attr = node.attributes;
for (const key in attr) {
var element = attr[key];
// 如果属性有v-model
if (element.nodeName === 'v-model') {
// 获取v-model绑定的属性值
var value = element.nodeValue;
// 把vm里data的value值给当前节点的vlaue
// node.value = vm.data[value]
new InputWatcher(value, node, vm);
// 设置监听input
node.addEventListener('input', function (e) {
vm.data[value] = e.target.value;
})
}
}
// 更深层次的遍历
if (node.childNodes.length !== 0) {
node.childNodes.forEach(child => compile(child, vm))
}
}
// 当前节点为text
if (node.nodeType === 3) {
// 检测是否符合正则
if (reg.test(node.nodeValue)) {
// 检测到后会自动封装到RegExp对象
var name = RegExp.$1;
name = name.trim();
// 去vm里取对应的值并修改
// node.nodeValue = vm.data[name];
// 每个节点设为一个观察者
new TextWatcher(name, node, vm);
}
}
}
// 把真实dom劫持到文档片段中,同时会把每个节点都编译
function nodeToFragment(node, vm) {
var flag = document.createDocumentFragment();
var child;
while (child = node.firstChild) {
// 每层节点都会进行编译
compile(child, vm);
// 把编译后的节点放入文档片段里
flag.appendChild(child);
}
return flag;
}
// 定义vue构造函数
function Vue(options) {
this.data = options.data;
observe(this.data, this);
var id = options.el;
// 传入真实dom,处理完后返回
var dom = nodeToFragment(document.getElementById(id), this);
// 最后替换app里的内容
document.getElementById(id).appendChild(dom);
}
// 定义主题
function Dep() {
this.subs = [];
this.addSubs = function (sub) {
this.subs.push(sub);
}
this.notify = function () {
this.subs.forEach(sub => {
sub.update();
})
}
}
// 定义文本节点类型观察者
function TextWatcher(name, node, vm) {
this.update = function () {
// 此次获取会触发get方法
this.value = this.vm.data[name];
this.node.nodeValue = this.value;
}
Dep.target = this;
this.name = name;
this.node = node;
// 从哪里去更新数据
this.vm = vm;
// new的时候会自己更新一次
this.update();
Dep.target = null;
}
// 定义输入框类型观察者
function InputWatcher(name, node, vm) {
this.update = function () {
// 此次获取会触发get方法
this.value = this.vm.data[name];
this.node.value = this.value;
}
Dep.target = this;
this.name = name;
this.node = node;
// 从哪里去更新数据
this.vm = vm;
// new的时候会自己更新一次
this.update();
Dep.target = null;
}
function defineReactive(obj, key, val) {
console.log(obj, key, val);
// 每新增一个监听相当于新增一个主题
var dep = new Dep();
// 响应式的数据绑定
Object.defineProperty(obj, key, {
get: function () {
if (Dep.target) {
dep.addSubs(Dep.target);
}
return val;
},
set: function (newVal) {
if (newVal === val) {
return;
} else {
// 把旧值更新
val = newVal;
dep.notify();
}
}
});
}
function observe(obj, vm) {
Object.keys(obj).forEach(function (key) {
defineReactive(obj, key, obj[key]);
});
}
var vm = new Vue({
el: 'app',
data: {
text: 'hello world',
wth: "wth"
}
})
</script>
</html>
主要过程
(1)在实例化vue对象时,我们为每一个data的属性都会创建一个主题类,并且设置get(用来往主题类增加观察者),set(用来通知更新观察者的数据)监听方法
(2)把实际节点截取到文档片段中,编译每个节点,按照个人规则编译的同时,创建观察者,在获取数据时,触发get方法,把自身加入主题类中,完成依赖收集,以后每次在更新data的数据时就会更新节点上的值。
38.package.json里字段释义,main是其他包引用时说明的地址,bin是在安装此包时如果是全局安装则可以直接在命令行执行命令,本地安装则通过父包的script去执行node-module里的包
39.commander用法:commander可以该文件在命令行启动后面的参数
#! /usr/bin/env node
var program = require('commander');
program
.option('dev, --git [type]', 'Add [marble]', 'Angie')
.parse(process.argv);
// 解析process.argv参数,把第二个参数后的参数封装,遇到dev使用git接收使用其中[]为可选参数,<>为必选参数,第三个参数为--help,第四个参数为默认值
if (program.git) console.log(' - git',program.git);
之后在package.json增加bin(作用是在全局安装时npm会生成软连接让其可以在命令行使用键名启动)用npm link实现预发布,
40.npm link相当于npm install -g,在包里使用则使用npm link xxxx
41.AMD、CMD、CommonJs、ES6的对比
AMD、CMD、CommonJs是ES5中提供的模块化编程的方案,import/export是ES6中定义新增的
AMD
//编写一个module1.js文件
//定义独立的模块
define({
methodA: function() {
console.log('我是module1的methodA');
},
methodB: function() {
console.log('我是module1的methodB');
}
});
//编写一个module2.js文件
//另一种定义独立模块的方式
define(function () {
return {
methodA: function() {
console.log('我是module2的methodA');
},
methodB: function() {
console.log('我是module2的methodB');
}
};
});
//编写一个module3.js文件
//定义非独立的模块(这个模块依赖其他模块)
define(['module1', 'module2'], function(m1, m2) {
return {
methodC: function() {
m1.methodA();
m2.methodB();
}
};
});
//再定义一个main.js,去加载这些个模块
require(['module3'], function(m3){
m3.methodC();
});
//我们在一个html文件中去通过RequireJS加载这个main.js
//等号右边的main指的main.js
<script data-main="main" src="require.js"></script>
//浏览器控制台输出结果
我是module1的methodA
我是module2的methodB
RequireJS:是一个AMD框架,可以异步加载JS文件,按照模块加载方法,通过define()函数定义,第一个参数是一个数组,里面定义一些需要依赖的包,第二个参数是一个回调函数,通过变量来引用模块里面的方法,最后通过return来输出。
是一个依赖前置、异步定义的AMD框架(在参数里面引入js文件),在定义的同时如果需要用到别的模块,在最前面定义好即在参数数组里面进行引入,在回调里面加载
define定义模块,return去导出,require导入
CMD
通过define()定义,没有依赖前置,通过require加载,CMD是依赖就近
// CMD
define(function(require, exports, module) {
var a = require('./a');
a.doSomething();
// 此处略去 100 行
var b = require('./b'); // 依赖可以就近书写
b.doSomething();
// ...
})
// CMD引入
seajs.use("./module1");
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething();
// 此处略去 100 行
b.doSomething();
//...
})
// AMD引入
require(["./module1"], function(){});
CommonJS
Nodejs端是使用CommonJS规范的,前端浏览器一般使用AMD、CMD、ES6等定义模块化开发的,不用定义,默认输出—module export 和带有名字的输出—exports.area,require引入
ES6
export 和 export defalut/import对模块进行导出导入的
42.ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的
r
e
f
s
对
象
上
。
如
果
在
普
通
的
D
O
M
元
素
上
使
用
,
引
用
指
向
的
就
是
D
O
M
元
素
;
如
果
用
在
子
组
件
上
,
引
用
就
指
向
组
件
实
例
:
43.
m
o
u
n
t
e
d
不
会
承
诺
所
有
的
子
组
件
也
都
一
起
被
挂
载
。
如
果
你
希
望
等
到
整
个
视
图
都
渲
染
完
毕
,
可
以
用
v
m
.
refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例: 43.mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.
refs对象上。如果在普通的DOM元素上使用,引用指向的就是DOM元素;如果用在子组件上,引用就指向组件实例:43.mounted不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用vm.nextTick 替换掉 mounted:
44.封装组件时,宽度会继承,高度不会,如果不设高度,内部会撑开外部,如果设置高度,则会突出,一般用100%去继承父亲,relative是不会脱离文档流的,写组件时尽量由内部撑开,父亲盒子的overflow:hidden会把盒子里的绝对定位隐藏掉(前提是子盒子是相对于这个父盒子里的任何元素,如果相对于body,则无法隐藏),而不会隐藏掉fixed的,绝对定位虽然已经脱离了文档流但是会撑开整个页面。
45.this.$el表示当前组件节点,element ui中在pop显示时会把当前pop组件增加到body节点最后,所以该组件一直都相对于body
46.如果父子盒子都是flex,那么子盒子会继承父盒子的高度
47.
1.babel是将es6转换成es5,转换后的代码遵循COMMONJS规范,浏览器是不能识别的,直接运行会报错;但是babel编译之后的代码体积较小;
2.借助webpack编译打包,可以实现代码在浏览器上运行但打包体积较大。
48.前端路由的原理:可以监听hash,也可以使用history的pushState,replaceState这些都不会刷新浏览器。
49.call的用法
function a(s,b){
this.a = s;
this.b = b;
this.sum = function (){
console.log(this.a + this.b)
}
}
var f = new a(1,2)
f.sum()
var a = 4;
var b = 6;
f.sum.call(this,null);
50.自定义事件:比如自创一个事件,可以挂到window对象上或者该对象的方法上
// 定义一个新的事件
var e = new Event("wth");
// window.aaa = e;
window.history.pushState = e;
// 监听这个事件
window.addEventListener("wth",() => {
console.log("触发了")
})
window.dispatchEvent(e);
51.监听history的pushState和replaceState方法
var wthPushState = function () {
var s = window.history.pushState;
return function () {
var wth = new Event("wth");
var r = s.apply(this, arguments);
wth.arguments = arguments;
window.wth = wth;
window.dispatchEvent(wth);
return r;
}
}
window.history.pushState = wthPushState();
window.addEventListener("wth", (e) => {
console.log('e', e);
})
52.mounted会在created方法中同步执行完毕后执行,异步不会等待,如果created被async修饰,则会在awit处暂停,去执行完后面的代码,再回去执行awit的代码,如果awit后面跟的不是promise则会直接执行该方法后的方法
async function b(){
console.log(2)
await setTimeout(function(){
console.log("4");
}, 1000);
console.log(5)
}
b();
console.log(3);
53.vue中函数式组件:
无状态,无实例(无this)
export default {
name: 'funtional-button',
functional: true,
render(createElement, { children }) {
return createElement('button', children)
}
}
第二个参数有以下对象
props
children
slots (a slots object)
parent
listeners
injections
data
54.transition只能由事件触发,而动画可以一加载就执行
55.
56.在分支上修改一行代码,合并别的分支无法清除这一行代码
57.npm有个根目录放着全局安装的包,在包被安装时或者npm link(会在跟目录创建快捷方式)会为操作系统创建软连接(如果该包的package.json中存在bin字段则注册),使得在命令行直接使用注册的键便可直接放问该文件,因为文件是js所以需要在文件上注释#!/usr/bin/env node让操作系统使用node去解析。删除软连接时全局删除该包即可。
58.vue里再操作完dom后无法立即获取值,同样,在用dom改变元素样式后如果再用数据驱动,之前的步骤会覆盖数据驱动
59.scrollwidth和ScrollHegiht取得是内容撑开的最大值,scrollleft和scrolltop都是必须要当前元素overflow:hidden才有用
60.函數表达式是变量提升,函数提升优先于变量提升且不会被变量声明覆盖,但是会被变量赋值之后覆盖。
61.怪异盒子模型是固定的,getBoundingClientRect和浏览器获取的都是该元素的包括边框和padding的,浏览器默认使用box-sizing: content-box并且不继承,在通过getBoundingClientRect获取值后给style设置,注意前后值不对应。
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div
id="test"
style="
width: 100px;
height: 100px;
background-color: blue;
border: 10px solid black;
box-sizing: border-box;
"
></div>
</body>
</html>
<script>
console.log("style", document.getElementById("test").style.width);
console.log(
"get",
document.getElementById("test").getBoundingClientRect().width
);
</script>
62.z-index只在本div有效
63.
64.如果maxAge为负数,则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。maxAge为负数的Cookie,为临时性Cookie,不会被持久化,不会被写到Cookie文件中。Cookie信息保存在浏览器内存中,因此关闭浏览器该Cookie就消失了。Cookie默认的maxAge值为–1。
如果maxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除,
设置cookie的secure属性为true,当设置了secure=true时,那么cookie就只能在https协议下装载到请求数据包中,在http协议下就不会发送给服务器端
65.innerHTML会解析里面的标签,但不会解析换行符,innerText会解析换行符,js里字符串字面量也会保留换行符
66.浏览器缓存策略由服务器返回的响应头设置,本地node服务器没有设置响应头所以不会有缓存,但是正式的文件服务器会这是缓存策略,所以每次发布都需要改变资源请求后缀。
67.
68.十进制97和字符a二进制都是一样的,只是取出来后解出来不一样
69.
70.hash改变不会请求资源,history只存每次的url映射值
71.fixed一般相对于浏览器窗口,但是如果父节点设置了transform则会相对于父节点,使用margin: auto;
left: 0;
right: 0;
top: 0;
bottom: 0;可以让fixed居中
72.Object.prototype->Function.prototype->Function->Object
73.defer是“渲染完再执行”,async是“下载完就执行”
74.
var s;
function a() {
var s = 1;
return b;
}
function b() {
console.log("s", s);
}
a()();// undefined
var s;
function a() {
var s = 1;
return function b() {
console.log("s", s);
};
}
a()();//1
75.编译器的"传名调用"实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数,它是"传名调用"的一种实现策略,用来替换某个表达式,让这个表达式在使用时再执行
76.HTML5 新的规定,是可以允许本地获取到跨域脚本的错误信息的,但有两个条件:一是跨域脚本的服务器必须通过 Access-Control-Allow-Origin 头信息允许当前域名可以获取错误信息,二是网页里的 script 标签也必须指明 src 属性指定的地址是支持跨域的地址,也就是 crossorigin 属性。有了这两个条件,就可以获取跨域脚本的错误信息:
77.原型链继承会共享属性,盗用构造函数继承不是父类的实例,组合继承与寄生组合继承的区别是寄生组合继承会抛弃父类的实例属性只要原型上的方法。
78.// vue先进入初始化状态,先初始化生命周期和事件,然后初始化inject,再初始化
// props、data、methods、computed、watch,最后初始化provid,注意此时data数据的依赖只会收集$watcher和watch的依赖,
// computed的因为还没有进行模板解析没有触发get方法不会收集依赖。然后调用mount函数,
// 这时会new渲染watcher,渲染watcher的构造函数执行时,就把自己注册进target栈,然后updateComponent作为回调函数
// 注册完毕后,调用render函数时会访问数据,数据的get方法会被触发,然后就收集这个渲染watcher进入依赖管理器中。
// 渲染watcher呢会以vm._update(vm._render())为表达式参数,实列上的_render()就是生成vnode供实列的_update做patch处理后渲染
// 在数据变化后会去通知watcher的update方法,也就是该组件的以上方法。