// 先写个冒泡
function sort(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr
}
// arguments 参数
// 函数内部隐式存在一个 argument 参数, 其以为数组形式存有所有传入的参数。
// 示例代码:实现 python 里的 range() 函数, 用于方便 for(index in range(number)){}
function range() {
if (arguments.length == 2) {
var arr = [...new Array(arguments[1]).keys()];
for (i in arr) {
arr[i] += arguments[0];
}
return arr;
} else {
return [...new Array(arguments).keys()];
}
}
// 一、创建对象
// 创建对象方法1:字面量创建对象
var counter = {
name: "counter",
count: 0,
add: function() {
return ++this.count;
}
}
console.log(counter.add());
console.log(counter.add());
// 创建对象方法2:创建空对象
var counter = new Object();
counter.name = "counter";
counter.count = 0;
counter.add = function() {
return ++this.count;
}
console.log(counter.add());
console.log(counter.add());
// 创建对象方法3:构造函数
function Counter(name, count) {
this.name = name;
this.count = 0;
this.add = function() {
return ++this.count;
}
}
var counter = new Counter('counter', 0);
console.log(counter['add']());
console.log(counter.add());
// 二、闭包
//
// 简单闭包例子:
function fun_out(x) {
var x = 0;
function fun_in() {
x += 1;
return x;
}
return fun_in;
}
counter = fun_out();
console.log(counter());
console.log(counter());
// 通过闭包来解决 [(通过创建空对象来创建对象)时无法创建私有成员]的问题
var counter = new Object();
fun_list = (function() {
//两个私有成员
var count = 0;
var name = 'adder';
//四个闭包(方法)
function fun() {
count += (name == 'adder' ? 1 : -1);
return count;
}
function get_count() {
return count;
}
function ch_name(param) {
if (param == 'adder')
name = param;
else if (param == 'minus')
name = param;
return name;
}
function get_name(params) {
return name;
}
return [get_count, fun, ch_name, get_name];
})()
// 测试
counter.get_count = fun_list[0];
counter.fun = fun_list[1];
counter.ch_fun = fun_list[2];
counter.get_fun = fun_list[3];
console.log(counter.get_count(), counter.fun(), counter.get_count());
console.log(counter.get_fun(), counter.ch_fun('minus'), counter.get_fun());
console.log(counter.get_count(), counter.fun(), counter.get_count());
// 闭包实现对象
function Person(name, weight, height, age) {
var instance = {
name: name,
weight: weight,
height: height,
age: age,
sleep: function(instance) {
return function() {
console.log('my name is ' + name + '.I am sleeping');
}
}(),
eat: function(instance) {
return function() {
console.log('my name is ' + name + '.I am eating');
}
}(),
code: function(instance) {
return function() {
console.log('my name is ' + name + '.I am coding');
}
}()
};
return instance;
}
zhangsan = Person('张三', '120', '175', '20');
console.log(zhangsan);
zhangsan.sleep();
zhangsan.eat();
zhangsan.code();
// 遍历对象属性及方法
for (element in counter) {
console.log(element, counter[element]);
}
obj.forEach((element) => {
console.log(element, obj[element]);
});
Object.keys(obj).forEach(element => {
console.log(element, obj[element]);
});
// 三、常用对象
// 1. Math 对象
// 补充 :到整数 parseInt() 到数字 Number() 强制转换
// Number 保留小数方法 Number.toFixed(小数位)
// 应用
function math() {
this.max = function(arr) {
if (arr.length < 0)
return undefined;
max = arr[0];
for (num of arr) {
max = num > max ? num : max;
}
return max;
}
this.random = function(min, max) { //取随机数
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
var math = new math();
arr = [1]
// 构造数列
for (i in [...new Array(10).keys()]) {
arr.push(math.random(55, 1000));
}
console.log(math.max(arr));
console.log(math.random(1, 1000));
// 2. Date 对象
var date = new Date();
// 获取时间常用方法
date.getFullYear();
date.getMonth(); //0~11
date.getDate();
date.getDay(); //0~6
date.getHours();
date.getMinutes();
date.getSeconds();
// 获取时间戳
date.valueOf();
date.getTime();
+new Date();
Date.now(); // H5新增,兼容性不好
// 倒计时
function countdown(date_str) {
sec = (+new Date(date_str) - +new Date()) / 1000;
return [parseInt(sec / 60 / 60 / 24), parseInt(sec / 60 / 60 % 24), parseInt(sec / 60 % 60), parseInt(sec % 60)]
}
date = new Date('2020-02-21 12:24:56')
console.log(countdown(date.valueOf()));
// 3. 数组对象
// 创建数组
var arr = [1, 2, 3, 4];
var arr = new Array(2, 3); //参数两个及以上为数组内容,一个为数组长度
//instanceof 运算符
console.log(arr instanceof Array
//Array的方法isArray
var integer = 1;
console.log(Array.isArray(integer));
// 添加删除数组元素
// 1.push方法,入栈,返回数组长度
console.log(arr.push('push1', 'push2'));
console.log(arr);
//2.pop方法,出栈,返回 值(value)
console.log(arr.pop());
console.log(arr);
// 3.unshift 方法,添加到头,返回数组长度
console.log(arr.unshift('unshift1', 'unshift2'));
console.log(arr);
// 4.shift方法,删除头,返回数组长度
console.log(arr.shift());
console.log(arr);
// 反转数组,reverse 方法,返回数组
console.log(arr.reverse());
// 排序,sort方法,提供一个比较函数
arr = [1]
for (i in [...new Array(10).keys()]) {
arr.push(math.random(55, 1000)); //构造数列
}
console.log(arr.sort(function(a, b) {
return a - b;
}));
// 正取索引,indexOf方法
console.log(arr.indexOf(1));
// 倒取索引,lastIndexOf
console.log(arr.lastIndexOf(1));
// 去重算法
function unique(arr) {
var newarr = [];
for (member of arr) {
if (newarr.indexOf(member) === -1) {
newarr.push(member)
}
}
return newarr
}
console.log(unique([111, 222, 111, 1, 1, 1, 1, 1, 12, 2, 2, 2, 2, 12]));
// 数组转换为字符串
// 1.toString方法
console.log([12, 3].toString());
// 2.join方法,参数指定分隔符
console.log([1, 2, 3].join(''));
// 其他数组方法
// concaat() 连接数组
// slice(begin, end) 截取数组
// spllice(begin, num) 删除指定位置的开始的数个元素
// spllice(begin, num, newData) 替换指定位置的开始的数个元素
// 4. 字符串对象
var str = '123456789abcABC啊'
console.log(str.length); //length属性返回字符个数,而不是字节个数
console.log(str.indexOf('12', 4)); //第二个参数为查找起始位置
// 根据索引返回 字符 / ascii
console.log(str.charAt(3));
console.log(str.charCodeAt(3));
console.log(str[3]); //h5新增,存在兼容性问题
// 方法
console.log(str.concat('连接字符串')); //连接字符串
console.log(str.substr(2, 1)); //截取字符串,参数:(索引, 长度)
console.log(str.replace('1', '替换')); //替换字符串
console.log(str.repeat(10)); //重复字符串,参数重复为次数
console.log(str.split('3')); //通过分隔符转换数组
console.log(str.toLocaleUpperCase()); //转换为大写
console.log(str.toLocaleLowerCase()); //转换为小写
// 补充:
str.includes('str') // 是否包含子串,返回 bool
// 返回出现最多次数的字符及次数
function exists_max(str) {
var chars = {};
for (char of str) {
if (chars[char]) {
chars[char] += 1;
} else {
chars[char] = 1;
}
}
var maxcount = 0;
var maxchar = '';
for (char in chars) {
if (chars[char] > maxcount) {
maxcount = chars[char];
maxchar = char;
}
}
if (maxchar === '')
return -1;
return {
char: maxchar,
count: maxcount
};
console.log(exists_max('abcddddadfdhgfd'));
// 一、获取元素
// 常用
document.getElementById('')
document.getElementsByTagName('')
document.getElementsByName('')
// H5 新增
document.getElementsByClassName('')
document.querySelector('')// 所有选择器均可,返回第一个找到的对象
document.querySelectorAll('')// 所有选择器均可,返回第找到的对象集合
// 获取特殊标签
console.log(document.body);
// 二、事件回调
//
// 鼠标相关
document.getElementById('button').onclick = function button1() {
var count = 1;
return function() {
console.log('你点击了按钮' + count++ + '次');
}
}()
document.getElementById('button').onmouseover = function button1() {
var count = 1;
return function() {
console.log('你经过了按钮' + count++ + '次');
}
}()
document.getElementById('button').onfocus = function button1() {
var count = 1;
return function() {
console.log('按钮获取了焦点' + count++ + '次');
}
}()
document.getElementById('button').onblur = function button1() {
var count = 1;
return function() {
console.log('按钮失去了焦点' + count++ + '次');
}
}()
document.getElementById('button').onmousemove = function button1() {
var count = 1;
return function() {
console.log('你在按钮上移动了鼠标' + count++ + '次');
}
}()
document.getElementById('button').onmousemdown = function button1() {
var count = 1;
return function() {
console.log('你按下了按钮' + count++ + '次');
}
}()
document.getElementById('button').onmouseon = function button1() {
var count = 1;
return function() {
console.log('你松开了按钮' + count++ + '次');
}
}()
// 事件解绑
// obj.onclick = null
// 补充:
// 'mouseover' 事件,进入子盒也会触发
// 'mouseenter' 鼠标进入元素触发,进入子元素不会触发
// 'mouseleave' 鼠标离开元素触发,离开子元素不会触发
// 原理,over 事件会冒泡,子元素会冒泡到父元素。
// enter 和 leave 事件不会冒泡,故不会触发父元素
// 再补充:
// ‘mousewheel’ 事件,鼠标物理滚轮滚动
// 三、元素属性
// 1. innerText innerHTML
// innerHTML保留html标签文本(推荐)
// innerText不保留html标签文本
// 2. 表单属性
// 禁止
input.disabled = true / false
input.value
input.checked
input.type
input.select
// 实例: 按下显示密码
document.getElementById('button').onmousedown = function() {
document.getElementById('input').type = 'text';
}
document.getElementById('button').onmouseup = function() {
document.getElementById('input').type = 'password';
}
// 3.修改样式
// 分别指定 style 样式
this.style
// css 封装好后直接指定类名
this.className
// 4.获取属性与自定义属性
// 获取和设置属性值
obj.Attribute
// 仅获取标签名称(XM L中返回原始大小写,HTML 中始终返回 **大写** ),node.nodeName 可获取任意节点的值
obj.tagName
// 自定义属性,h5规范要求自定义属性以 data- 开头
// 获取自定义属性值
obj.getAttribute('attribute_name')
// h5新增: (所有自定义属性的集合,集合内属性名会自动去掉 data- 前缀,且其他 - 连接的单词会变成驼峰吗命名)
obj.dataset
// 设置自定义属性值
obj.setAttribute('attribute_name', value)
// 四、节点操作
// 节点拥有 nodeType nodeName nodeValue等属性
// nodeType: 元素节点为1 属性节点为2 文本节点为3
// ----一、获取节点----
// 取父节点
obj.parentNode 获取父节点
// 取子节点
1. obj.childNodes // 获取所有子节点,包含文本节点(回车等)无用信息,取元素节点只能通过nodeType来判断是否为元素节点
2. obj.children // 获取所有子元素节点
3. obj.firstChild // 获取第一个子节点,包含文本节点
4. obj.lastChild // 获取最后一个子节点,包含文本节点
5. obj.firstElementChild // 获取第一个元素节点,ie9以上
6. obj.lastElementChild // 获取最后一个元素节点,ie9以上
// 取兄弟节点
1. obj.nextSibling // 获取下一个兄弟节点,包含文本节点
2. obj.previousSibling // 获取上一个兄弟节点,包含文本节点
3. obj.nexElementSibling // 获取下一个兄弟元素节点,ie9以上
4. obj.previousElementSibling // 获取上一个兄弟元素节点,ie9以上
// ----二、创建节点----
// 创建元素节点
1. dom.creatElement('tagName')
2. dom.write(element str) // 文档执行完毕后调用会直接重绘文档,且文档内容仅包含参数
3. obj.innerHTML = element str // 向节点内直接写入element
// 效率 3 > 1,注意 innerHTML 方式效率虽然高,但拼接字符串会花费非常多的时间,创建多个标签应通过数组实现
// 可以直接对新创建的元素的 innerHTML 赋值来添加当新元素内的元素
// 如:
dom.creatElement('li').innerHTML = '<a href="javascript:;"> text </a>';
// 添加节点
1. obj.appendChild(child) // 插入至node的子元素末尾
2. obj.insertBefore(child, other) // 插入至node的other元素之前
// 删除节点
obj.removeChild(child) // 子元素将一并删除
// 复制节点
obj.cloneNode() // 浅拷贝
obj.cloneNode(true) // 深拷贝
// - - -
// 阻止链接跳转
// 1. href属性填写 javascript:; 或 javascript:void(0); (或者填写一个无意义的字符如##, 1等)
// 2. href填写#或空,添加属性onclick值为 return false,即为其添加回调函数返回false阻止跳转(返回true为允许跳转)
// = = =
// 五、事件回调高级
// 1. 事件侦听与解绑
// 事件侦听
obj.addEventListener('event_name', callback, bool) 标准
obj.attachEvent('event_name', callback) 非标准,ie9之前独有
// 事件解绑(与上方对应)
obj.removeEventListener('event_name', callback)
obj.detachEvent('event_name', callback)
// 2. DOM 事件流
// 事件触发后会向全体元素广播回调,广播存在顺序执行的两种时序:
// 1. 由根节点到子节点(捕获)
// 2. 由子节点到根节点(冒泡)
// obj.onclick 与 obj.attachEvent() 仅在冒泡阶段触发
// obj.addEventListener() 可通过第三个参数来设置函数将处于哪种时序中被回调
// 捕获阶段: true 冒泡阶段: false (缺省)
// 大部分情况下不会使用捕获阶段
// onblur、onfocus、onmouseenter、onmouseleave 不会在冒泡时序中被回调
// 3. 事件对象
// 回调时作为参数传入
document.getElementById('event_obj').addEventListener('click', function(event) {
console.dir(event || window.event); // 兼容性处理,ie9以前需要从 window 对象中取到事件对象
console.log({// 常用属性及方法
'触发对象:': event.target,
// ie9之前不支持 兼容性处理|| event.srcElement,若考虑兼容性,还应使用 obj.onclick 注册事件
// 有可能是子元素触发
'绑定对象:': this,
'绑定对象:': event.currentTarget,
// 非标准,ie9之前不支持,一般使用this
'事件类型:': event.type,
'-------------': '-------------',
'阻止默认行为:': event.preventDefault,
// ie9之前不支持,使用方法 e.returnValue,
// 另外通过 obj.onclick 的回调中返回 false 也可阻止默认行为
'阻止冒泡:': event.stopPropagation
// ie9之前不支持,使用属性 e.cancelBubble = true
});
});
// 4. 事件委托 /(jQuery 称事件委派
// 给父亲注册事件,回调时判断事件对象的 target 属性
obj_father.addEventListener('click', function(e) {
if (event.target == ...') {
// ...
console.log('我被触发了:' + event.target);
}
// 补充:
// 事件触发后会有一个全局变量 event 出现,与传入回调函数的事件对象完全相同
console.log(e);
console.log(event);
console.log(e === event);
});
// 5. 鼠标事件高级
// 鼠标事件对象常用属性
1. clientX clientY 相对于客户区的xy坐标
2. pageX pageY 相对于文档的xy坐标 ie9之前不支持
3. screenX screenY 相对于屏幕的xy坐标
// 鼠标事件
1.contextmenu 右键菜单被触发
2.selectstart 文本选择开始
3.mousemove 鼠标被移动
4.mousedown 鼠标按下
5.mouseup 鼠标抬起
//demo 阻止
阻止右键菜单及选择的文本
// 禁止右键菜单
document.getElementById('forbid').addEventListener('contextmenu', function(e) {
e.preventDefault();
});
// 禁止文本选择
document.getElementById('forbid').addEventListener('selectstart', function(e) {
e.preventDefault();
});
// 6. 键盘事件高级
// keydown 键盘按下
// keyup 键盘弹起
// keypress 键盘按下,不识别功能键
// 执行顺序 keydown > keypress
document.addEventListener('keyup', function(e) {
// 键盘事件对象常用属性
console.log({
'按下的键:': e.key,
// 返回按下的键,有很大兼容性问题
'按下的ascii:': e.keyCode,
// 返回按下键的 ascii,keypress 区分大小写,keyup 和 keydown 不区分大小写
});
});
// 另:手动调用 obj.{event(click)}()
// 一、BOM 基础
// 1. 变量、函数分别为 window 对象的方法
// 注意:name 是window对象的一个属性 console.log(window.name);
// 注意: 定时器传入的函数由 window 对象回调
// 2. BOM 事件 'load' 页面完全加载完成后回调
// 通过关键字 'load' 注册或直接对 window.onload 赋值函数指针
// 另:DOM 事件 'DOMContentLoaded'仅 DOM 加载完后回调 ie9及以上支持
// 3. BOM 事件 'resize' 窗口大小被改变时回调
// 通过关键字 'resize' 注册或直接对 window.onresize 赋值函数指针
// 回调函数中通过 e.width 和 e.height 获得窗口当前大小
// 4. BOM 事件 'pageshow' 页面被重新加载时回调
// 火狐中存在'往返缓存',后退时不会触发 load 系事件
// 回调函数中通过 e.persisted 属性可以判断页面是否来源于缓存
// 5. 定时器
// 定时 window.setTimeout(callback, timeout) timeout 缺省为0 返回一个句柄,指向此定时器
// 停止定时 window.clearTimeout(hWnd)
// 重复定时 window.setInterval(callback, timeout)
// 6. 异步
function asyn_demo() {
temp = function() {
console.log(1);
// 第一个执行
setTimeout(() => {
console.log(2);
//第五个执行
}, 0);
console.log(3);
//第二个执行
console.log(4);
//第三个执行
}();
console.log(5);
//第四个执行
};
// webapi的异步任务将在主线程空闲时执行
// 二、常用对象
// 1. location 对象
// window.location 对象常用方法属性
console.log({
'href(url)': location.href, // *常用
'host(域名)': location.host,
'port(端口)': location.port,
'pathname(路径)': location.pathname,
'search(query参数)': location.search, // *常用
'hash(#link)': location.hash,
'-------------': '-------------',
'assign() 跳转,记录浏览历史': location.assign,
'replace() 跳转,不记录浏览地址': location.replace,
'reload() 重载': location.reload // 参数传入 true 则不读取缓存
});
// 2. navigator 对象
console.log({
'Agent': navigator.agent
});
// 3.history 对象
console.log({
'forward()(前进)': history.forward,
'back() (后退)': history.back,
'go() (跳转)': history.go //参数为前进后退的
});
// 三、js 网页特效
// offset系列
// 1. obj.offsetParent 带有定位的父元素,若无返回body
// 2. obj.offsetTop 距父元素(有定位)顶端的距离(**带边框** 不带margin)
// 3. obj.offsetLeft 距父元素(有定位)左端的距离(**带边框** 不带margin)
// 4. obj.offsetWidth 元素宽度(**带边框** 不带margin)
// 5. obj.offsetHeight 元素高度(**带边框** 不带margin)
// client系列
// 1. obj.clientWidth 元素宽度(**不带边框** 不带margin)
// 2. obj.clientHeight 元素高度(**不带边框** 不带margin)
// 3. obj.clientTop 上边框宽度
// 4. obj.clientLeft 左边框宽度
// scroll系列
// 1. obj.scrollHeight 元素实际内容大小(包含超出边框的部分)(**不带边框** 不带margin)
// 2. scrollWidth (包含超出边框的部分)(**不带边框** 不带margin)
// 3. obj.scrollTop 元素上方被卷曲的内容高度
// 4. obj.scrollLeft 元素左边被卷曲的内容高度
// 另: 'scroll' 事件,元素被滚动
// 另: 页面被卷曲的内容高度需要通过 window.pageYOffset 及 window.pageXOffset 获取 ie9及以上支持
// 兼容性解决方法
// 声明了 DTD,通过 document.documentElement.scrollTop/Left 获取
// 未声明 DTD,通过 document.body.scrollTop/Left 获取
// 封装
function get_scroll(params) {
return {
Left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
Top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
};
}
// js 动画
animate_event = function(obj, length, target, velocity, interval, callback) {
function animate(obj, length, target, velocity, interval, callback) {
if (target === undefined) {
var target = length + obj.offsetLeft;
}
obj.timer = setInterval(() => {
if (obj.offsetLeft != target) {
step = (target - obj.offsetLeft) / velocity;
obj.style.left = obj.offsetLeft + (step < 0 ? Math.floor(step) : Math.ceil(step)) + 'px';
} else {
callback && callback();
clearInterval(obj.timer);
}
}, interval);
}
return function(e) {
clearInterval(obj.timer);
animate(obj, length, target, velocity, interval, callback);
}
};
// js 滚动条平滑滚动,本页面的自动滚动即由此代码实现
function scrollSmooth(y, velocity, interval, callback, stopScroll = true) {
// local 声明
if (stopScroll) {
if (typeof stop_scroll === 'undefined') {
stop_scroll = function (e) { // 事件回调函数
e.preventDefault();
};
}
} else {
if (typeof get_state === 'undefined') {
var fun_list = function () {
var state = false; // false 用户未滚动
return [
function () { // get state
return state;
},
function (state_) {
return function () { // set state
state = state_;
};
}
];
}();
var get_state = fun_list[0];
var set_state = fun_list[1];
}
}
function animate(y, velocity, interval, callback) {
if (stopScroll) {
document.addEventListener('mousewheel', stop_scroll, {
passive: false
});
} else {
temp_fun = set_state(true);
set_state(false)();
// PC 端
document.addEventListener('mousewheel', temp_fun);
document.addEventListener('DOMMouseScroll', temp_fun);
// 移动端
document.addEventListener('touchstart', temp_fun);
}
this.timer = setInterval(() => {
if (!stopScroll) {
if (get_state() === true) { // 判断用户滚动
clearInterval(this.timer);
document.removeEventListener('mousewheel', temp_fun);
callback && callback();
return;
}
}
if (Math.abs(window.pageYOffset - y) > 1) { // 滚动过程
var step = (y - window.pageYOffset) / velocity;
window.scroll(0, window.pageYOffset + (step < 0 ? Math.floor(step) : Math.ceil(step)));
} else {
callback && callback();
clearInterval(this.timer);
if (stopScroll) {
document.removeEventListener('mousewheel', stop_scroll);
}
}
}, interval);
}
return function () {
clearInterval(this.timer);
if (stopScroll) { // 清除事件回调
document.removeEventListener('mousewheel', stop_scroll);
} else {
if (typeof temp_fun !== 'undefined') {
document.removeEventListener('mousewheel', temp_fun);
}
}
animate(y, velocity, interval, callback);
};
}