代码-函数前的各种符号
/* 常见的函数调用 */
(function () { })(); // 没有返回值的函数默认返回undefined
/* 【!】 对返回值的真假取反 */
console.log(!function () { return }()); // true,undefined属于false
console.log(!function () { return 0 }()); // true(取反操作)
console.log(!function () { return 1 }()); // false(取反操作)
/* 【+ -】 对返回值进行数学运算 */
console.log(+function () { return 5.1 }()); // 5.1
console.log(-function () { return 5.1 }()); // -5.1
/* 【~】 对返回值按位取反 */
// 所有正整数的按位取反是本身 +1 的负数, 所有负整数的按位取反是本身 +1 的绝对值,0 的按位取反是 -1
console.log(~function () { return 5 }()); // -6
console.log(~function () { return -5 }()); // 4
console.log(~function () { return 0 }()); // -1
代码-各种运算符
// 【双问号运算符】
/*
作用是当一个表达式是 null 或者 undefined 时为变量设置一个默认值
这个运算符只会在左侧表达式是 null 或 undefined 时返回右侧的表达式
空值合并运算符会允许把 0 和空字符串作为有效的数值。
*/
let bx = { name: 'abc' };
// bx.name ??='123'; // 存在将不赋值覆盖 不存在则创建
// 【三元运算符】
var isNull = null; console.log(isNull ?? 'content');
n > 1 ? true : false // 单个判断
n > 1 ? 'Big' : n < 1 ? 'Small' : false; // 多个判断
/* 或运算符,与运算符 */
function inputCheck(e) {
const val = e.key || "Not Found KeyName";
console.log(val);
}
var obj = { k: "这是一个键值" };
inputCheck(obj);
// 【||】
/*
1.没写||的情况:不存在的键名,默认返回undefined
2.写||情况: 不存在的键名,会执行后面语句 (类似于??)
【例子】
false / 0 || "value" >>> "value"
true / 1 || "value" >>> true
undefined / null / NaN || "check" >>> "check"
Infinity || else >>> Infinity
const value=e.key; // bad solution
const value = e.key || ''; // good solution
*/
// 【&&】
/*
true / 1 && "code" >>> "code" (if简写方法)
false / 0 && "value" >>> false
Infinity && "code" >>> "code"
if(condition){expression} // Bad Solution
codition && expression // Good Solution
*/
代码-defer/async区别
/* defer与async区别: */
/*
defer:
当前页面解析完成之后才执行js代码
特别是比较大的脚本,提高整个网页的载入速度是非常明显
async:
在当前js文件加载完成后,执行js代码
*/
/* 方法1 */
// 这种加载方式执行完之前会阻止onload事件的触发
(function () {
var scriptEle = document.createElement("script");
scriptEle.type = "text/javasctipt";
scriptEle.async = true;
scriptEle.src = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
var x = document.getElementsByTagName("head")[0];
x.insertBefore(scriptEle, x.firstChild);
})();
/* 方法2:onload异步加载 */
// 这种方法只是把插入script的方法放在一个函数里面
// 然后放在window的onload方法里面执行,这样就解决了阻塞onload事件触发的问题。
(function () {
if (window.attachEvent) {
window.attachEvent("load", asyncLoad);
} else {
window.addEventListener("load", asyncLoad);
}
var asyncLoad = function () {
var ga = document.createElement("script");
ga.type = "text/javascript";
ga.async = true;
ga.src =
("https:" == document.location.protocol ? "https://ssl" : "http://www") +
".google-analytics.com/ga.js";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(ga, s);
};
// asyncLoad ();
})();
/* 方法3:Promise异步加载 */
// Promise提供了一种更合理、更强大的异步解决方案
var success = false;
const p = new Promise(function (resolve, reject) {
if (success) {
resolve("成功的结果");
} else {
reject("失败的结果");
}
});
p.then(
function (res) {
console.log("接收resolve传来的数据....");
},
function (err) {
console.log("接收reject传来的数据....");
}
);
p.catch(function (err) {
console.log("接收reject传来的数据或者捕获到then()中的运行报错时");
});
p.finally(function () {
console.log(">>>>>>>>>>>");
});
/* 方法4:自定义异步加载 */
// (封装一个函数兼容性的异步加载js文件并且可以按需执行该文件里面的函数(按需加载))
function loadScript(url, callback) {
var script = document.createElement("script");
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == "complete" || script.readyState == "loaded") {
callback();
}
};
} else {
script.onload = function () {
callback();
};
}
script.src = url;
document.body.appendChild(script);
}
url = "http://cdn.bootcss.com/jquery/3.0.0-beta1/jquery.min.js";
function fc() {
console.log("此函数运行状态...");
}
loadScript(url, fc);
代码-call/applly/bind区别
/* 参数 */
/*
call(object,参数);
apply(object,[数组参数]);
bind(objet,参数)();
*/
/* 例子1 */
var c = { v: '测试内容' };
function callBack(s) { console.log(this.v + ' ' + s); };
callBack.call(c, 'call:content');
callBack.apply(c, ['apply:content']);
callBack.bind(c, 'bind:content')();
/* 例子2(进阶) */
var he = { name: '德玛', code: 4 };
var me = {
name: '剑圣', code: 10,
myFun: function (from, city) {
console.log(
this.name + ' 编号:' +
this.code, '来自:' +
from + ' 去往:' +
city
);
}
};
me.myFun.call(he, '联盟', '水晶');
me.myFun.call(me, '联盟', '水晶');
/* 例子3(bind进阶) */
function mj(n2, n3) { return console.log(this.x, n2, n3); };
var m = mj.bind({ x: 10 }, 20);
m(30);
代码-null/undefined/Infinity/NaN
/* null */
/*
无值|初始化变量
null表示'没有对象',即该处不应该有值。
用来初始化一个变量,这个变量可能被赋值为一个对象。
当函数的参数期望是对象时,被用作参数传入。
函数的返回值期望是对象时,被用作返回值传出
【区别】 Undefined 与 null 的值相等,但类型不相等
*/
/* undefined */
/*
未声明|未赋值
undefined表示'缺少值',就是此处应该有一个值,但是还没有定义。
变量被声明了,但没有赋值时,就等于undefined。
调用函数时,应该提供的参数没有提供,该参数等于undefined。
对象没有赋值的属性,该属性的值为undefined。
函数没有返回值时,默认返回undefined。
【区别】 Undefined 与 null 的值相等,但类型不相等
*/
/* Infinity */
/*
JavaScript 在计算数时超出最大可能数范围时返回的值
*/
/* NaN */
/*
属于JavaScript保留词,指示某个数不是合法数
*/
代码-var/let/const区别
/* var */
/*
关键词声明的变量没有块作用域
在块 {} 内声明的变量可以从块之外进行访问
定义的全局变量属于 window 对象
在相同的作用域,或在相同的块中,通过 var 重新声明一个 let 变量是不允许
声明的变量会进行变量提升
不存在关键性死区
【共同】【var,let】函数作用域,全局作用域
*/
/* let */
/*
关键词声明拥有块作用域的变量
在块 {} 内声明的变量无法从块外访问
定义的全局变量不属于 window 对象
在相同的作用域,或在相同的块中,通过 let 重新声明一个 let 变量是不允许
声明的变量不会进行变量提升
存在关键性死区
【共同】【var,let】函数作用域,全局作用域
*/
/* const */
/*
与 let 变量类似,但不能重新赋值
在块 {} 内声明的变量无法从块外访问
无法重新声明声明或赋值
*/
代码-事件捕获与事件冒泡区别
/* 事件捕获与事件冒泡区别 */
{
/* 基本了解 */
/*
阻止事件的冒泡方法 event.stopPropagation() 不让事件向document上蔓延
阻止事件冒泡 // function fc(ev) { var en = ev || event; en.cancelBubble = true;};
addEventListener(event,func,false); // 默认为false
冒泡:false
捕获:true
例子: box 包含 item
冒泡:里->向上延申(点击item,先触发item,后触发box)
捕获:外->向下趋势(点击item,先触发box,后触发item)
*/
}
代码-鼠标坐标点细节
/* x,y/clientX,clientY/pagex,pageY/offsetX,offsetY/screenX,screenY区别: */
/*
鼠标坐标点 x,y
鼠标坐标点(__不随滚动条改变而改变__) clientX,clientY
鼠标坐标点(__随滚动条滚动而改变__) pageX,pageY
鼠标坐标点(__相对于目标元素边缘位置__) offsetX,offsetY
鼠标坐标点(__相对于显示器(手机/电脑/其它)屏幕__) screenX,screenY
*/
代码-元素的尺寸细节
/* screen.width/offsetWidth/clientWidth/innerWidth/outerWidth区别: */
/*
clientWidth 返回该元素的像素宽度,宽度包含padding,不包含border,margin和滚动条,是一个整数,单位是像素 px。
offsetWidth 返回该元素的像素宽度,宽度包含padding,border,不包含margin,是一个整数,单位是像素 px。
innerWidth 返回窗口的文档显示区的宽度,如果有水平滚动条,也包括滚动条高度。
outerWidth 属性设置或返回窗口的外部宽度,包括所有的界面元素(如工具栏/滚动)。
screen.width 属性声明了显示浏览器的屏幕的宽度
*/
代码-遍历细节
/* map与forEach */
/*
1.map速度比forEach快
2.map会返回一个新数组,不对原数组产生影响,foreach不会产生新数组,forEach返回undefined
3.map因为返回数组所以可以链式操作,forEach不能
4.map里可以用return
*/
/* 参数列表 */
/*
every: 是否全部通过测试
some: 其中一个是否通过测试
filter: 返回新数组,通过测试的有哪些
map: 返回新数组-所有元素进行修改(返回true|false)
forEach: 按顺序为数组中的每个元素调用一次函数
reduce: 函数的返回值存储在累加器中(结果/总计),通常应用统计(加减乘除)的总和
*/
// every 是否全部通过测试(&&)
var numbers = [45, 24, 29, 26, 25];
var p_every = numbers.every(f_every);
function f_every(value, index, array) {
return value > 18;
}
console.log(p_every); // >>> true
// some 其中一个是否通过测试 (||)
var numbers = [45, 4, 9, 16, 25];
var p_some = numbers.some(f_some);
function f_some(value, index, array) {
return value > 18;
}
console.log(p_some); // >>>true
// filter 返回新数组-通过测试的有哪些
var numbers = [45, 4, 9, 16, 25];
var p_filter = numbers.filter(f_filter);
function f_filter(value, index, array) {
return value > 18;
}
console.log(p_filter); // >>> [ 45, 25 ]
// map 返回新数组-所有元素进行修改 / 进行大小判断-返回true|false
var numbers = [45, 4, 9, 16, 25];
var p_map = numbers.map(f_map);
function f_map(value, index, array) {
return value * 2;
}
console.log(p_map); // >>> [ 90, 8, 18, 32, 50 ]
// forEach 按顺序为数组中的每个元素调用一次函数
var txt = "";
var numbers = [45, 4, 9, 16, 25];
numbers.forEach(f_foreach)
function f_foreach(value, index, array) {
return txt = txt + value + "-";
}
console.log(txt) // >>> 45-4-9-16-25-
// reduce 将数组的值减为单个值(从左到右) / 函数的返回值存储在累加器中(结果/总计)
var numbers = [15.5, 2.3, 1.1, 4.7];
var p_reduce = numbers.reduce(getSum);
function getSum(total, num) {
return total + num;
}
console.log(p_reduce); // >>> 23.6
/* 区别 */
let box = [1, 2, 3, 4, 5];
console.log(box.map((item) => 2 * item)); // >>> [ 2, 4, 6, 8, 10 ]
console.log(box.filter((item) => item > 2)); // >>> [ 3, 4, 5 ]
console.log(box.find((item) => item > 2)); // >>> 3
console.log(box.every((item) => item < 5)); // >>> false
console.log(box.findIndex((item) => item === 3)); // >>> 2
console.log(Array.from(box, (item) => item * item)) // >>> [ 1, 4, 9, 16, 25 ]
代码-(==)/(===)区别
/*
=== 类型和值同时相等
== 值相等
*/
代码-String/toString区别
/* 区别 */
/*
toString 对 undefined,null 转换出错
String 相对 toString 更全面
*/
// 例子
(undefined).toString() // TypeError
(null).toString() // TypeError
代码-变量赋值/对象赋值区别
// 变量赋值
var b1 = 1, b2 = b1;
b2 = 2;
console.log(b1, b2);
// >>> 1 2
// 对象赋值
var r1 = { a: 1 }, r2 = r1;
r2.a = 2
console.log(r1.a, r2.a)
// >>> 2 2
代码-this细节
// 例子
let obj = {
a: function () {
// this指向obj
console.log(this);
},
b: () => {
// this指向window
console.log(this);
}
}
obj.a();
obj.b();
代码-防抖/节流区别
/* 区别 */
/*
同样延迟1秒后触发情况
防抖-1秒内无论如何快速点击,只有松开后才会触发,否则就不断重新开始计数为止
节流-无论如何快速点击,1秒就1次发生
应用:防抖-用户输入,节流-跳转页面
*/
/* 防抖 */
var fd = document.getElementById('fangdou');
var fdt = document.querySelector('#fangdou+p');
function fang_dou(fn, wait) {
let timeout = null;
return function () {
// 每一次点击判断有延迟执行的任务就停止
if (timeout != null) { clearTimeout(timeout); };
// 否则就开启延迟任务
fdt.innerHTML = '....';
timeout = setTimeout(fn, wait);
};
};
function fdtest() { fdt.innerHTML = '防抖成功'; };
fd.addEventListener('click', fang_dou(fdtest, 1000));
/* 节流 */
var jl = document.getElementById('jieliu');
var jlt = document.querySelector('#jieliu+p');
function jie_liu(fn, wait) {
let bool = true;
return function () {
if (!bool) { return };
bool = false;
setTimeout(() => {
//fn() fn中this指向window
fn.call(this, arguments);
bool = true;
}, wait);
};
};
function jltest() { jlt.innerHTML = '节流成功....'; };
jl.addEventListener('click', jie_liu(jltest, 1000));
代码-懒加载
// 懒加载-延迟加载,按需加载
var imgs = document.querySelectorAll('.box');
function lozyLoad() {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('top:', scrollTop);
var winHeight = window.innerHeight;
console.log('win:', winHeight)
for (let i = 0; i < imgs.length; i++) {
console.log(imgs[i].offsetTop, scrollTop, winHeight)
if (imgs[i].offsetTop < scrollTop + winHeight) {
//设置延迟 预留缓冲->效果对比
setTimeout(() => {
imgs[i].style.background = imgs[i].getAttribute('data-bg');
}, 1000)
//CSS-过渡效果
/*
imgs[i].style.transition='2s'
imgs[i].style.background=imgs[i].getAttribute('data-bg');
*/
}
}
};
window.onscroll = function () { lozyLoad() };
代码-promise
/* promise异步 */
/* 基本了解 */
/*
相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果
【特点】
1.对象的状态不受外界影响
2.处理异步的操作 三个状态: Pending 进行中/ Resolved 成功/ Rejected 失败
*/
/* 参数列表 */
/*
all 用于异步并行操作
race 用于请求超时操作
resolve 返回异步操作成功的结果
reject 回异步操作失败的结果
then 执行Promise状态是成功的操作(异步执行)
catch 执行Promise状态是失败的操作(异步执行)
finally 成功或失败都执行操作
done 始终执行
*/
// 例子1
let pro1 = new Promise(function (resolved, rejected) { });
console.log(pro1);
// 例子2:简单异步操作
let pro2 = new Promise(function (resolved, rejected) {
// 执行异步操作
let res = { code: 201, data: { name: '小马哥' }, err: '失败' };
setTimeout(() => {
if (res.code === 200) {
resolved(res.data);
} else {
rejected(res.err);
};
}, 1000);
});
console.log(pro2);
pro2.then((success) => { console.log(success); }, (err) => { console.log(err); });
// 例子3:异步并行操作(复杂)
let p1 = new Promise((resolve, reject) => { });
let p2 = new Promise((resolve, reject) => { });
let p3 = new Promise((resolve, reject) => { });
let p4 = Promise.all([p1, p2, p3])
p4.then(() => {
// 三个都成功 才成功
}).catch((err) => {
// 如果有一个失败 则失败
});
// 例子4:请求超时操作
// 请求图片资源
function requestImg(imgSrc) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = function () {
resolve(img);
};
img.src = imgSrc;
});
}
function timeout() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("图片请求超时"));
}, 3000);
});
}
// 参数:数组
Promise.race([requestImg("https://img1.baidu.com/it/u=1310564963,1641173348&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800"), timeout()])
.then((res) => {
// 3秒内请求成功 执行then方法
console.log(res);
document.body.appendChild(res);
})
.catch((err) => {
// 超过3秒 执行catch方法
console.log(err);
});
代码-async
/* async */
/* 作用 */
/*
使得异步操作更加方便
基本操作:async它会返回一个Promise对象 then catch
async是Generator的一个语法糖
*/
async function f() {
let s = await 'hello world'
let data = await s.split('')
return data;
}
f().then(v => console.log(v)).catch(e => console.log(e));
async function f2() { throw new Error('出错了'); };
f2().then(v => console.log(v)).catch(e => console.log(e));
代码-构造函数
/* 构造函数 */
// 数组
Array.prototype.len = function () { console.log(this.length) };
var arr = ['a', 'b', 'c'];
arr.len();
// 对象
Object.prototype.sum = function () { let sum = this.a + this.b + this.c; console.log(sum); };
var obj = { a: 1, b: 2, c: 3 };
obj.sum();
// 字符串
String.prototype.len = function () { console.log(this.length); };
var str = '123456789';
str.len();
代码-argument
// 例子1:函数参数查看
function fc() {
var x = 10, y = 20;
console.log(arguments[1]);
};
fc('abc', '123'); // >>> 123
// 例子2:阶乘的实现
var factorial = function (n) {
/**
* @注释 n === 1 必须返回1 否则n将无限迭代
* @function callee 返回正在被执行的函数对象,只能在相关的函数 执行时才能使用
* @应用 实行函数的递归
*/
return 1 === n ? 1 : n + arguments.callee(n - 1);
};
console.log(factorial(5)); // >>> 120
代码-Generator/Interator
/* Generator生成器/Interator迭代器 */
/*
生成器:
yield是JS为了解决异步调用的命令
表示程序执行到某个阶段会交出执行权,等待结果返回
需要在协程Generator函数中运行,函数名之前要加星号,以示区别
调用Generator函数,返回一个内部指针(遍历器g,执行不会返回结果,返回的是指针对象)
调用指针g的next方法,移动内部指针(执行异步任务的第一段)指向第一个遇到的yield语句
生成器不会立即执行,需要调用next()才会执行,调用return()则会终止生成器的运行
*/
/* generator */
// 例子1
function* gen(x) {
var y = yield x + 2;
return y;
};
var g = gen(1);
var n1 = g.next(); var n2 = g.next();
console.log(n1); console.log(n2);
// 例子2-快捷方法
function* foo() {
/* 方法1 yield 1; yield 2; yield 3; */
yield* [1, 2, 3];
};
var f = foo();
console.log(f.next().value);
console.log(f.next().value);
console.log(f.next().value);
// 例子3
function* add() {
console.log('start');
let x = yield '2'
console.log('one:' + x)
let y = yield '3'
console.log('two:' + y)
return x + y;
}
const fn = add();
console.log(fn.next());
console.log(fn.next(20));
/* interator */
const arr = ['one', 'two', 'three'];
// 创建新的迭代器
const item = arr[Symbol.iterator]();
console.log(item.next()); // one
console.log(item.next()); // two
代码-闭包
/* 基本了解 */
/*
函数和函数内部能访问到的变量的总和,就是一个闭包
*/
var local = '变量';
function foo() {
console.log(local)
};
代码-解构/展开/交换
/* 对象解构 */
// const { name, id } = obj
/* 数组展开 */
// ...arr
/* 变量交换 */
// [a, b] = [b, a]
代码-深拷贝/浅拷贝
/* 浅拷贝 */
/*
浅拷贝-只复制对象的第一层属性,深拷贝可以对对象的属性进行递归复制
浅拷贝只是拷贝了内存地址
浅拷贝增加了一个指针指向已存在的内存
子类的属性指向的是父类属性的内存地址
当子类属性修改后,父类属性也随之修改
*/
var a = { name: 'Jerry', age: 20 };
var b = a;
b.name = 'Tom';
console.log(a, b); // >>> { name: 'Tom', age: 20 } { name: 'Tom', age: 20 }
/* 深拷贝 */
/*
深拷贝可以对对象的属性进行递归复制,浅拷贝-只复制对象的第一层属性
深拷贝就是增加一个指针,并申请一个新的内存
并且让这个新增的指针指向这个新的内存地址使用深拷贝
当复制原对象但不能修改原对象的时候,就得使用深拷贝
*/
var c = { name: 'abc', n: '123' };
var d = JSON.parse(JSON.stringify(c));
d.name = 'def';
console.log(c, d); // >>> { name: 'abc', n: '123' } { name: 'def', n: '123' }
var text = ['123', '456', '789']
var new1 = JSON.parse(JSON.stringify(text))
new1[0] = '000'
console.log(new1) // >>> [ '000', '456', '789' ]
代码-ES6模块导出导入
/* 参数列表 */
/*
export 用于规定模块的对外接口
import 用户输入其它模块提供的功能
*/
// 例子1-基本配置
/*
Nodejs 安装 anywhere
终端:anywhere 自动配置localhost:port*
index.html(默认为主页)
*/
/* 方法1:常规导入 */
/*
// index.js
代码:
export const name = '张三'
export const age = 18
export function sayName(){ return 'my name' }
// index.html
代码:
<script type='module>
import {name,age,sayName} from './modules/index.js'
console.log(name,age,sayName())
</script>
*/
/* 方法2:展开导入 */
/*
// index.js
代码:
const name = '张三'
const age = 18
const function sayName(){ return 'my name'}
export{ name,age,sayName }
const obj={ foo:'foo'}
export default obj;
// index.html
代码:
import obj,{name,age,sayName} from './modules/index.js'
console.log(obj,name)
*/
/* 自定义命名 */
/*
import * as f from './modules/index.js'
console.log(f); console.log(f.default);
*/
代码-原型链
/* 参数列表 */
/*
constructor 对创建对象的函数的引用(指针),对于 Object 对象,该指针指向原始的 Object() 函数
Prototype 对该对象的对象原型的引用,对于所有的对象,它默认返回 Object 对象的一个实例。
hasOwnProperty 判断对象是否有某个特定的属性。必须用字符串指定该属性。
IsPrototypeOf 断该对象是否为另一个对象的原型
PropertyIsEnumerable 判断给定的属性是否可以用 for...in 语句进行枚举
ToString 返回对象的原始字符串表示。对于 Object 对象
ValueOf 返回最适合该对象的原始值。对于许多对象,该方法返回的值都与 ToString() 的返回值相同
*/
/* 原型链继承 */
function Parent() { this.a = 20 }
function Child() { this.b = 30 }
Child.prototype = new Parent()
let o2 = new Child()
console.log(o2, o2.name, o2.age)
代码-Solution
/* 假设-函数传递多个参数 */
{
/* Bad Solution */
// function fc(param1,param2,param3,param4,param5){...}
/* Good Solution */
// function fc({param1,param2,param3,param4,param5}){...}
// 函数参数放入对象里
}
/* 假设-合并数组 */
{
/* Bad Solution */
var arr1, arr2;
arr1 = arr1.concat(arr2)
/* Good Solution */
arr1 = [...arr1, ...arr2]
}