- 关于 a++ ,++a, a--, --a,
先运算还是先执行语句的问题.
当 ++a 时, 只要遇到语句中变量取值情况出现, 就先执行++a ,然后才会进行取值操作.
- 关于 a += b * c, a *= b + c;
相当于 a = a + ( b * c ); a = a * (b + c);
即, 注意一下运算顺序.
- function test () {} 自带一个属性name,
即, test.name 会返回 字符串类型的 'test',
需要注意的是,
var test = function abc () {},
定义成这样时,
abc 这个变量会提示是 未定义的变量.
但test.name 返回的却是 字符串 'abc'
- arguments 实参列表, arguments.length 返回实际参数的数量.
fn.length 返回形参的数量
- arguments 和 形参一一映射关系
实际上, 刚开始的时候是很容易理解的,
可到了后面学过引用值和原始值的特点之后,反而不太好理解.
function test (a) {
arguments[0] = 10;
console.log(a)/ 输出10
}
test(2)
- 关于toString 的一个细节认识的修正
null 和 undefined 因为没有原型链 所以无法调用 toString
而123.toString 会首先识别成浮点型,所以无法调用toString
我一直以为 123 即number类型之所以不能直接调用toString
是因为 123 不会临时转换成Number类对象的缘故,
而像下面这样则是可以的
var num = 123;
num.toString() ; /返回'123'
而true 则可以直接调用
true.toString() ; / 返回'true'
这种不统一当时我还觉得很奇怪, 现在明白了,
如果直接浮点型数据, 则能正常调用
123.1.toString() / 返回 '123.1'
- 关于call 的一个隐式类型转换
function test () {console.log(this)};
test() ;/ 返回 window
test.call(); / 返回 window
test.call(null); / 返回 window
test.call(undefined); / 返回 window
test.call({}); / 返回 window {}
test.call([]); / 返回 window []
到这里没什么问题, 没发生类型转换
到了原始值就有了
test.call(123); / 返回 Number {123}
test.call(''); / 返回 String {''}
test.call(true); / 返回 Boolean {true}
- document.styleSheet 这个对象不太明白.
-2.onclick 只能绑定一个函数, addEventListener 能绑定多个, onclick 能 覆盖add吗? -- 不会
-3. oncontextmenu 和 addEvent , 如果 前者把默认行为取消掉, 后者也会取消吗? -- 会, 表明默认事件的api 两者共同影响一个变量.
-4. 取消的默认事件, 还能返回嘛? -- 大神的回复 https://segmentfault.com/q/1010000004819075
-5. 回忆, 是否能用 for + let 解决闭包? 可以, 查看babel 的翻译,能看出就是用 立即执行函数解决的?
严格来讲, 这不能说是用闭包解决的问题, 因为没有把内部的函数传递给外部.
-6. 封装兼容的事件绑定函数
- document.styleSheet 这个对象不太明白.
function addEvent (div, type, handle,flag = false) {
if (window.addEventListener) {
div.addEventListener(type,handle,flag)
} else if (window.attachEvent) {
div.attachEvent("on" + type, function (e) {//因为 attachEvent 的 this 默认指向window, 所以这里更改一下.
handle.call(div,e);
})
} else {
div["on" + type] = handle;
}
}
-7. 假设一个ul>li结构, 用ul 进行事件委托, 但在 ul绑定事件时, 用事件捕获模式, 请问,事件发生时, target 是 ul 还是 li?
依然是li, 表明target与 冒泡机制和捕获机制无关.
-8. 同一个对象的同一个事件类型,上面绑定了两个事件处理函数,一个符合冒泡,一个符合捕获,点击一个元素后,是先捕获,还是先冒泡?先捕获, 后冒泡, 可以记为, 捕获用的是true, 冒泡用的是false, 设置的应该比默认的优先级高一点. 对target元素, 谁先绑定, 谁先触发.
- focus,blur,change,submit,reset,select 等事件不冒泡
9.1 能冒泡的事件 (非常全) - https://www.cnblogs.com/rubylouvre/p/5080464.html
- 取消冒泡 e.stopPropagation() e.cancelBubble = true;
- 阻止默认事件 return false event.preventDefault(); event.returnValue = false
- a标签阻止默认事件 <a href = “avascript:void( )”>
- srcelement和target
- input.value 和 input 的 e.value 是一个值? -- 废话, 当然不可能是一样的, e.value 的值为 undefined
- 练习题, 实现拖拽功能.
- 实际上, 通常最消耗时间的地方是, 边界关系,逻辑关系稍微复杂一点.
或者, 有些数学关系, 并不像其他问题一样, 是单纯的, 线性的, 而是涉及稍微多个量, 并且还要注意方向, 即, 需要对多个因素, 需要保持关注时
超出临时记忆范围时, 易出现这种情况.
解决方法是, 用文字, 或者用图片, 进行辅助思考. 大脑负荷会低很多, 效率就会高很多, 时间消耗就少一点.
- 鼠标事件, click, up, down的触发顺序, down -> up -> click.. 根据这个顺序, down和up 的时间差, 可以防止和click 的冲突
- 键盘事件触发顺序 keydown -> keypress -> keyup
- keydown 和 keypress 的区别?
keydown 监控所有按键, keypress 监控字符类按键,
keypress 能返回ask码
keydown 能通过 e.key 获得字符, 也能识别大小写
- 再次整理一下js中各种位置和几何尺寸相关的属性, 和api - //www.greatytc.com/p/fffa7a8efb22
- 按需加载js的函数封装, 有懒加载的意思. 跟JSONP也有点类似,(应该能跨域)
function loadScript (url,callback) {
var script = document.createElement('script');
script.type = "text/javascript";
if (script.readyState) {// 兼容ie
script.onreadystatechange = function (e) {
if (script.readyState == "complete" || script.readyState == "loaded") {
tools[callback]();
}
}
} else{
script.onload = function () {
tools[callback]();
}
}
script.src = url;
document.body.appendChild(script);
}
function loadScript (url,callback) {
var script = document.createElement('script');
script.type = "text/javascript";
if (script.readyState) {// 兼容ie
script.onreadystatechange = function (e) {
if (script.readyState == "complete" || script.readyState == "loaded") {
eval(callback);
}
}
} else{
script.onload = function () {
eval(callback);
}
}
script.src = url;
document.body.appendChild(script);
}
function loadScript (url,callback) {
var script = document.createElement('script');
script.type = "text/javascript";
if (script.readyState) {// 兼容ie
script.onreadystatechange = function (e) {
if (script.readyState == "complete" || script.readyState == "loaded") {
callback();
}
}
} else{
script.onload = function () {
callback();
}
}
console.log(script);
script.src = url;
document.body.appendChild(script);
}
-22 js 事件加载线
创建docuemnt对象, 解析文档.
document.readyState = "loading"
遇到 link css 异步加载, 解析文档
遇到 script 外部文件, 同步加载, 阻塞解析
遇到 script asyinc , 异步加载, 解析文档, 加载完成时立即执行
遇到 script defer , 异步加载, 解析文档, 解析完成时执行
遇到 img 等资源, 异步加载, 解析文档
当domtree解析完毕, document.readyState = "interactive" (表示可以交互了?) (此时执行defer script)
触发 document.DOMContentLoaded 事件, 标志, 同步脚本执行阶段, 转为事件驱动阶段.
全部加载完毕时, 触发 window.onload事件, document.readyState = "complete"
22.1 jQ中, $(document).ready() 和 window.onload的区别?
一个是解析完执行, 一个是加载完执行, 前者比后者反应快.
document.ready = function (callback) {
///兼容FF,Google
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', function () {
document.removeEventListener('DOMContentLoaded', arguments.callee, false);
callback();
}, false)
}
//兼容IE
else if (document.attachEvent) {
document.attachEvent('onreadystatechange', function () {
if (document.readyState == "complete") {
document.detachEvent("onreadystatechange", arguments.callee);
callback();
}
})
}
else if (document.lastChild == document.body) {
callback();
}
}
-23. 为什么 script 标签通常写在最下面?
- 同步加载时, 解析完就会执行, 操作dom时, 有可能找不到,而报错.
- js执行会阻塞页面渲染. 因为js是单线程
正则表达式
-24. 创建正则的两种方式
var reg = /abc/gmi;
var reg = new RegExp(str,"gim");// 优点, 可以传变量进去.
-25.1 深入理解正则 https://www.cnblogs.com/lizhenlin/p/6654934.html
-25.2 深度理解正则: 这个是大神, 从注释部分开始优点看不懂 https://www.cnblogs.com/zuoshaowei/p/6058955.html?utm_source=itdadao&utm_medium=referral
-25.3 正则表达式30分钟入门教程 http://deerchao.net/tutorials/regex/regex.htm
-25.4 注意 : /abc/g.test(str) 和 /abc/.test(str) 的表现是不一样的. 有g时, 会向后移动.会返回false
-25.5 习题 :写一个字符串,检验一个字符串首尾是否都含有数字 /^\d\w*\d$/
-26.6 习题 : 把 the-first-name 变成小驼峰式写法 theFirstName : 用 replace
var reg = /-(\w)/g;
var str = the-first-name;
str.replace(reg,function ($,$1) {return $1.toUpperCase()})
ES6 简书笔记文集 //www.greatytc.com/nb/32041352
-1. let,const : 暂时性死区, 不得重复声明, 无变量提升. ;解决闭包; let x = x 会报错
-2. 函数 : 参数默认值, 惰性求值.
-3. 惰性求值延伸 -- 求值策略(赋值策略) : 是个大神 https://www.cnblogs.com/TomXu/archive/2012/02/08/2341439.html
-4. 箭头函数,没有this,没有 arguments,没有super,没有prototype,不能被 new 操作符运算,call,apply,bind 也失去作用
-5. 箭头函数中 this指向,离自己最近的非箭头函数作用域中的this ,arguments与此类似,指向离自己最近的非箭头函数的arguments
-6. 箭头函数+setTimeout 配合, 可以不用处理this
-7. 几种迭代方式
-7.1 for i++ ,, 遍历数组
var arr = [1,2,3];
var len = arr.length;
for(var i = 0; i < len; i++) {
console.log(arr[i]);
}
-7.1.1 forEach , 遍历数组
var arr = [1,2,3];
arr.forEach((item,index) => {
console.log(item);
})
-7.2 for in 遍历对象
var obj = {name : "mike"};
for(var key in obj) {
console.log(obj[key]);
}
防止遍历原型链上的
var obj = {name : "mike"};
for(var key in obj) {
if(obj.hasOwnProperty(key)){
console.log(obj[key]);
}
}
-7.3 for of 用来遍历 迭代器 , 不能用来迭代对象, 用来迭代数组会丢失第一个?
function* fibs() {
let a = 0;
let b = 1;
while(true) {
if (a > 100) {
/如果没有限制条件, 下面的 for of 会死循环.
return "over"
}
yield a;
[a, b] = [b, a + b];
}
}
let i = fibs();
for(let item of i){
console.log(item);
}
-7.4 解构赋值, 可以迭代 对象, 数组, 迭代器(迭代器内部调用的是next);
-7.4.1 使用解构赋值时, 会遍历原型链上的属性.
-7.5 对象的遍历
ES6 一共有 5 种方法可以遍历对象的属性。
(1)for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上的 5 种方法遍历对象的键名,都遵守同样的属性遍历的次序规则。
首先遍历所有数值键,按照数值升序排列。
其次遍历所有字符串键,按照加入时间升序排列。
最后遍历所有 Symbol 键,按照加入时间升序排列。
-7.5 原型相关的API
Object.setPrototypeOf(obj, proto);
Object.getPrototypeOf(this).foo
Object.createObject(proto)
let [a,b,c,d,e] = fibs();
let {name : s } = obj;
let [a,b] = arr;
let [...arr] = arr1; // 完成浅克隆 arr == arr1 返回false
-7.5 字符串扩展
-CharAt(num),
-charCodeAt(num);// 返回该字符的unicode码,
- str.slice(start,end); [start,end) 左闭右开
- str.indexOf(txt,start=0);
- str.includes(txt,start=0)
- str.startWith(txt,start=0)
- str.endWith(txt,end=length)
- str.repeat(num);
-7.6 模板字符串 : 跟函数配合时的应用需要加强.
-7.7 数组的扩展 - Array.of() 增强版 new Array() 生成数组
- Array.from() 将类数组转换为数组 arguments Nodelist
- 类数组转成数组, 也可以用扩展运算符 let realArr = [...oDivList];
- arr.find((item,index,self) => {})
- arr.findIndex((item,index,self) => {}) 遇到符合条件的马上停止
- arr.fill(value, start=0,end=length) 常用于初始化操作.
生成器, 迭代器
-1. 可迭代的数据类型 arr,set,map,
-2. 可返回迭代器的 函数 entry(), keys(), values()
-3. 内部api : next 返回值 {value,done}
-4. for of 用于迭代迭代器
-5. 内部隐式生成迭代器 for(let value of arrSymbol.iterator)
-6. 无法用for of 遍历两次同一个迭代器, 但可以迭代arr,set,map , 因为每次会生成新的迭代器arrSymbol.iterator
-6.1 str 没有 entry(),keys(),values() , 但拥有 strSymbol.iterator, 所以可以用 for of 迭代.
-7. 字符串可用 for of迭代, 双字节字符 , for in 不可
-8. 生成器为函数, 返回的数据为迭代器.
-9. return 能够终止 next
-10 委托迭代器
function *pro (arr,string) {
yield * arr;
yield * string;
}
let i = pro([1,2,3,4],'abcdef');
class
-1. 可以返回一个可迭代的数据!
class iteratorArray {
constructor (arr = []) {
this.arr = arr;
}
*[Symbol.iterator](){// 通过定义这个属性, 就可以让数据可迭代. 可以调用next, 可以 for of
yield *this.arr[Symbol.iterator]()
}
}
let arr = new iteratorArray([1,2,3]);
for(let item of arr) {
console.log(item);
}
Promise
-模拟封装Promise //www.greatytc.com/p/029217e15481
es6 习题 //www.greatytc.com/p/5db01aa0fa52
-1. 链表和数组的区别 : 链表 地址是 非连续的, 数组的内存是 连续的.
-2. 类数组转数组的方法 : 之前最常用的是 [].slice.call(arguments),es6中的数组扩展符, [...arguments],Array.from(arguments);
-3. 解构赋值的用途 : https://www.cnblogs.com/fireporsche/p/6288796.html
SCSS 中文教程 - https://www.sass.hk/docs/
-1. 层级结构
-2. & 指向父级
-3. @name 变量
-4. @extend 继承
-5. 控制语句 @if @else-if ,@each ,@ for from through @while
-6. 混合指令 @mixin --- @include
vue 生命周期- 钩子
-1. beforeCreate created beforeMount mounted beforeUpdate updated beforeDestroy destroyed
一些增加理解的模拟封装
1. 模拟数组的迭代器
let arr = [1,2,3,4,5];
function createIterater (arr = []) {
let nextIndex = 0;
return {
next(){
if (arr.length - 1 < nextIndex ) {
return {
value : undefined,
done : true
}
}else{
return {
value : arr[nextIndex++],
done : false
}
}
}
}
}
let nod = createIterater(arr);
2. 生成器 + 模板字符串的应用, 非常的秀
function first () {
console.log('first ing');
setTimeout(function () {
console.log("first");
},1000)
}
function second () {
console.log('second ing');
setTimeout(function () {
console.log("second");
},2000)
}
function third () {
console.log('third ing');
setTimeout(function () {
console.log("third");
},1000)
}
function *createIterator () {
let result = `${yield first()}${yield second()}${yield third()}`;
console.log(result);
}
let process = createIterator();
3. class + 迭代器
class iteratorArray {
constructor (arr = []) {
this.arr = arr;
}
*[Symbol.iterator](){// 通过定义这个属性, 就可以让数据可迭代. 可以调用next, 可以 for of
yield *this.arr[Symbol.iterator]()
}
}
let arr = new iteratorArray([1,2,3]);
for(let item of arr) {
console.log(item);
}
4. 模拟封装Promise
class myPromise {
constructor (fn) {
if (typeof fn !== "function") {
throw TypeError(`myPromise resolver ${fn} is not a function`)
}
this.state = "pending";
this.data = undefined;
this.resolveCB = [];
this.rejectCB = [];
let resolve = (data) => {
if (this.state == "pending") {
setTimeout(() => {
this.state = "resolved"
this.data = data;
this.resolveCB.forEach(fn => fn());
},0)
}
}
let reject = (data) => {
if (this.state == "pending") {
setTimeout(() => {
this.state = "rejected"
this.data = data;
this.rejectCB.forEach(fn => fn());
},0)
}
}
fn(resolve,reject);
}
then (resolveFn, rejectFn) {
if (this.state == "resolved") {
let rus = resolveFn(this.data);
if (rus instanceof myPromise) {
return rus
}else{
return myPromise.resolve(rus);
}
}
if (this.state == "rejected") {
let rus = rejectFn(this.data);
if (rus instanceof myPromise) {
return rus
}else{
return myPromise.resolve(rus);
}
}
if (this.state == "pending") {
return new myPromise((resolve, reject) => {
console.log(this.resolveCB);
this.resolveCB.push(((resolveFn)=>{
return () => {
var res = resolveFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(resolveFn));
this.rejectCB.push(((rejectFn)=>{
return () => {
var res = rejectFn(this.data);
if (res instanceof myPromise) {
res.then(resolve,reject);
} else{
resolve(res)
}
}
})(rejectFn));
})
}
}
static resolve (data) {
return new myPromise((suc) => {
suc(data);
})
}
static reject (data) {
return new myPromise((suc,err) => {
err(data);
})
}
}
webpack 基础配置
// node 自带路径模块.
var path = require("path");
// 插件必须 在这里引入
var HtmlWebpackPlugin = require("html-webpack-plugin");
var uglify = require("uglifyjs-webpack-plugin");
var MiniCss = require("mini-css-extract-plugin");
// 模块化导出格式
module.exports = {
// 配置入口文件
entry: {
main: "./src/index.js"
},
// 配置出口文件
output: {
// 出口文件名
filename: "[name].js",
path: path.resolve(__dirname, "dist") //__dirname 指的是根目录.dist 设置出口文件夹.
},
// 配置 环境变量, 设置为开发环境
// 导出的文件不是压缩的
mode: "development",
// 设置为生产环境,导出的文件是压缩的.
//mode : "production"
// 开启服务器时,默认打开dist文件下的index.html
// 自动刷新页面
devServer: {
contentBase: "dist",
// 更改 端口
port: 9879
},
// 应用loader
module: {
rules: [
// css loader
{
// 正则匹配需要转换的文件类型
test: /\.css$/,
// 使用的加载器, 顺序是从右向左,css-loader 用来解析 css style-loader 用来注入style标签?
use: [MiniCss.loader, 'css-loader']
},
// {
// test : /\.html$/,
// use : [
// {// 单独抽离的文件,进行处理生成文件
// loader : 'file-loader',
// options : {
// name : "index.html"
// }
// },
// {// 单独抽离html文件
// loader : 'extract-loader'
// },
// {//找到 html文件
// loader : 'html-loader'
// }
// ]
// },
// es6 js loader
// {
// test : /\.js$/,
// use : ["babel-loader"]
// },
// 图片 loader 字体loader
{
test: /\.(jpg|png)$/,
use: [{
loader: "url-loader",
options: {
//小于该大小时,生成url码,大于时,生成独立文件.
limit: 8912,
// 独立文件的文件夹,以及名称和格式.
name: "/img/[name].[ext]"
}
}]
}
]
},
plugins: [
new HtmlWebpackPlugin({
// 设置title
title : "title",
template : "./src/index.html"
}),
new uglify(),
new MiniCss({
// contenthash:8 根据内容生成八位数哈希值.
filename : "[name]_[contenthash:8].css"
})
]
}
常用vue 用例
<div id="app">
<p>{{ number }}</p>
<input type="button" name="btnGetNumber" value="增加" v-on:click="getNumber()">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
number: 1
},
methods: {
// 事件响应方法的逻辑代码
getNumber: function (e) {
this.number += 1; // 不管是内联方法调用,还是绑定事件处理器两种方式执行事件响应方法的时候 this都是指向 app
}
},
watch: {
// 监控number的变化,并自动执行下面的函数
number: function (val, oldVal) {
console.log('val:' + val + ' - oldVal: ' + oldVal);
}
}
});