1.定义对象
工厂模式
-
优:接受参数,可以无数次的调用这个函数
-
缺:没有解决对象识别的问题(即怎么知道一个对象的类型)
function createPerson(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.sayName = function () { } return o; } var person1 = createPerson("Lin", 22, "Student"); person1.sayName();
构造函数模式
-
优:它的实例标识为一种特定的类型
-
缺:每个方法都要在每个实例上重新创新一遍
function Person(name, age, job) {
this.name = name;
this.age = age;
this.sayName = function () { }
}
var person1 = new Person("Lin", 22, "Stduent");
person1.sayName();
原型模式
-
优:减少了代码的重复,也可用标识来创建对象
-
缺:所有实例默认取得相同的属性值
function Person() { }
Person.prototype = {
constructor: Person,
name: "Lin",
age: 22,
friends: ["Shelby", "Court"],
sayName: function () { }
}
var person1 = new Person();
person1.friends.push("Van");
组合模式,构造+原型(推荐)
this.job = job;
this.age = age;
this.friends = ["Shelby", "Court"];
Person.prototype = {
constructor: Person,
sayName: function () { }
}
var person1 = new Person("Lin", 22, "Student");
var person2 = new Person("Ququ", 22, "Student");
person1.friends.push("Van");
2.实现继承
组合、寄生组合、构造、实例、原型链、拷贝
function Animal(name) {
this.name = name;
this.sleep = function () { }
}
1、组合继承(推荐)
function Cat1(name) {
Animal.call(this);
this.name = name;
}
Cat1.prototype = new Animal();
Cat1.prototype.constructor = Cat1;
var cat = new Cat1();
2、寄生组合继承(推荐)
function Cat2(name) {
Animal.call(this);
this.name = name;
}
(function () {
//创建一个没有实例方法的类
var Super = function () { };
Super.prototype = Animal.prototype;
//将实例作为子类的原型
Cat6.prototype = new Super();
})();
var cat = new Cat2();
3、构造继承
function Cat3(name) {
Animal.call(this);
this.name = name;
}
var cat = new Cat3();
4、实例继承
function Cat5(name) {
var instance = new Animal();
instance.name = name;
return instance;
}
var cat = new Cat5();
5、原型链继承(不推荐)
Animal.prototype.eat = function () { }
3.es5、es6实现继承
www.jb51.net/article/239072.htm
1、原型链继承
缺点: (1)每个实例对引用类型属性的修改都会被其他的实例共享
(2)在创建Child实例的时候,无法向Parent传参。这样就会使Child实例没法自定义自己的属性(名字)
2、借用构造函数(经典继承)
优点: (1)解决了每个实例对引用类型属性的修改都会被其他的实例共享的问题
(2)子类可以向父类传参
缺点: (1)无法复用父类的公共函数
(2)每次子类构造实例都得执行一次父类函数
3、组合式继承(原型链继承和借用构造函数合并)
优点: (1)解决了每个实例对引用类型属性的修改会被其他的实例共享的问题
(2)子类可以向父类传参
(3)可实现父类方法复用
缺点: 执行两次父类构造函数,第一次是Child.prototype = new Parent(), 第二次是Parent.call(this, name)造成不必要的浪费
4、原型式继承
缺点: 同原型链继承一样,每个实例对引用类型属性的修改都会被其他的实例共享
5、寄生式继承
缺点: 同借用构造函数一样,无法复用父类函数,每次创建对象都会创建一遍方法
6、寄生组合式继
优点: 不必为了指定子类型的原型而调用父类型的构造函数
ES6类继承
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
toString() {
return this.x + '' + this.y
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y)
//调用父类的
constructor(x, y)
this.color = color
}
toString() {
return this.color + ' ' + super.toString()
调用父类的toString()
}
}
var colorPoint = new ColorPoint('1', '2', 'red')
console.log(colorPoint.toString()) //red 12
4.对5种数据类型复制
function clone(obj) {
var o;
switch (typeof obj) {
case "undefined": break;
case "string": o = obj + ""; break;
case "number": o = obj - 0; break;
case "boolean": o = obj; break;
case "object":
//判断对象(Object)或数组(Array)
if (obj === null) {
o = null;
} else {
if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {
o = [];
for (var i = 0; i <= obj.length; i++) {
o.push(clone(obj[i]));
}
} else {
o = {};
for (var k in obj) {
o[k] = clone(obj[k]);
}
}
}
break;
default: o = obj; break;
}
return o;
}
5.统计字符串字符
//统计字符串中字符个数和出现次数最多的字符
function s(str) {
var obj = {};
for (var i = 0; i < str.length; i++) {
var chars = str.charAt(i);
if (obj[chars]) {
obj[chars]++;
} else {
obj[chars] = 1;
}
}
console.log(obj);
var ch = '';
var max = 0;
for (var k in obj) {
if (obj[k] > max) {
max = obj[k];
ch = k;
}
}
console.log('最多的字符是' + ch + ":" + max);
}
6.清除字符串前后的空格
trs.trim(); //存在小部分不兼容
str.replace(/(^\s)|(\s)$/gm, '')
7.判断字符串回文
function palindRome(str) {
var len = str.length,
str1 = "";
for (var i = len - 1; i >= 0; i--) {
str1 += str[i];
}
}
8.递归
阶乘
function factroial(n) {
if (n = 1) return 1;
return n * factorial(n - 1)
}
求和
function sum(n) {
if (n == 1) return 1;
return n + sum(n - 1)
}
斐波拉契数列(0、1、1、2、3、5...)
function fib(n) {
if (n == 1 || n == 2) return n - 1
return fib(n - 1) + fib(n - 2)
}
爬楼梯(每次1、2步,共n步)
function climbStairs(n) {
if (n == 1) return 1
if (n == 2) return 2
return climbStairs(n - 1) + climbStairs(n - 2)
}
深拷贝
function clone(n) {
var temp = {}
for (var i in n) {
if (typeof n[i] == 'object' ||
typeof n[i] == 'Array') {
temp[i] = clone(n[i])
} else {
temp[i] = n[i]
}
}
return temp
}
9.阻止事件冒泡
事件捕获(往下传播),事件冒泡(往上传播),捕获 => 目标事件 => 冒泡
< html @clik="box" > <body @clik="box" >
<div @clik="box" > 它们都绑定了点击事件</div >
</body ></html >
function box() {
event.stopPropagation();//阻止冒泡,不阻止捕获
event.preventDefault(); //阻止捕获,不阻止冒泡
return false; //都阻止
}
var box1 = document.getElementsByTagName('div')
box1.addEventListener('clik', function (), false)
//第三个参数,false允许冒泡,true允许捕获,应用各个标签
10.检测数据类型
function getType(target) {
var ret = typeof (target);
var template = {
"[object Array]": "array",
"[object Date]": "date",
"[object RegExp]": "regexp",
"[object Object]": "object"
}
if (target === null) {
return 'null';
} else if (ret == "object") {
var str = Object.prototype.toString.call(target);
return template[str];
} else {
return ret;
}
}
11.10~100选取随机数并排序
var Array = [];
function getRandom(num1, num2) {
var transition = num2 - num1;
//Math.floor向下取整,
//Math.random() 生成[0,1)随机数
var res = Math.floor(Math.random() * transition + num1);
return res;
}
for (var i = 0; i < 10; i++) {
Array.push(getRandom(10, 100));
}
Array.sort(function (a, b) {
return b - a;
})
12.rem手机端适配
function adaptive() {
var styleN = document.createElement("style");
var width = document.documentElement.clientWidth / 16;
styleN.innerHTML = 'html{font-size:' + width + 'px!important}';
document.head.appendChild(styleN);
}
手机屏幕分16份,每份代表1rem,设计图宽度/16就是1rem。以iphone6宽750px为
1rem=750px/16=46.875px
60px/46.875px= 1.28rem
css写法
.box{ width: 60px; width: 1.28rem; }
less写法
@rem: 46.875rem; body{ width: 60 / @rem; }
13.JS延迟加载的方法
1.defer、async属性
< script defer src = 'script.js' ></script >
defer : 等html全部解析完成,才会执行js代码,顺次执行js脚本。
async: async是和html解析同步的(一起的),不是顺次执行js脚本(谁先加载完谁先执行)。
2.动态创建DOM方式(使用多)
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
//添加监听事件,三种事件模型,DOM0,DOM2,IE
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;
3.使用setTimeout延迟方法
setTimeout(function () {
window.location.reload();
}, 3000);
4.让JS最后加载
置于 < body > 底部,加快Dom加载,避免JS出错Dom无法加载
14.字符串驼峰命名
function toString(foo) {
//根据某个字符进行切割多个字符串
var arr = foo.split('-');
//每个字符串第一个字母转换成大写,首字母大写+后续字母
for (var i = 1; i < arr.length; i++) {
arr[i] = arr[i].charAt(0).toUpperCase() +
arr[i].substr(1, arr[i].length - 1)
}
//根据某个字符将数组转成字符串
return arr.join('');
}
15.添加、移除、移动、复制、创建和查找节点
(1)创建新节点
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
(2)添加、移除、替换、插入
appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入
(3)查找
getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性
querySelector() //id、class、标签
//querySelector() 方法仅仅返回匹配指定选择器的第一个元素。如果你需要返回所有的元素,请使用 querySelectorAll() 方法替代。
16.伪数组转标准数组
伪数组又称类数组,是一个类似数组的对象Object,length属性是静态的,不会随着成员的变化而改变,不具有数组的push(), forEach()等方法
1、函数内部的 arguments
2、DOM 对象列表 ,例 document.getElementById( )获取的 dom元素
3、jQuery对象 如 $('div')
const divs = document.querySelectorAll('div')
1.for循环
let arr = [];
for (let i = 0; i < divs.length; i++) {
arr.push(divs[i]);
}
2.数组slice.call()
const arr = [].slice.call(divs);
const arr = Array.prototype.slice.call(divs);
3.ES6 Array.form()
const arr = Array.from(divs)
4.ES6 扩展运算符...
const arr = [...divs]
17.数组去重
1、双重for循环
function distinct(arr) {
for (let i = 0, len = arr.length; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] == arr[j]) {
arr.splice(j, 1);
len--; j--;
//splice 会改变数组长度,所以-1
}
}
};
return arr;
}
2、Array.filter() 加 indexOf
function distinct(arr) {
return arr.filter((item, index) => {
return arr.indexOf(item) === index
//filter过滤不合格,indexOf根据item值返回下标
})
}
3、ES6‘...’和‘Set’
...结构Set对象为数组,Set对象自动去除重复值
function unique(arr) {
return [...new Set(arr)];
}
4、键值对
function distinct(arr) {
var obj = {},
arr1 = [];
return arr.filter(function (item, index, arr) {
return obj.hasOwnProperty(typeof item+item) ? false : (obj[typeof item+item] = item)
});
//hasOwnProperty判断obj有无该属性,没有就添加
//对象转数组
for (const key in obj) {
arr1.push(obj[key])
}
}
18.数组排序
1、快速排序
function quicksort(arr) {
//4.判断数组的长度,小于1 停止执行
if (arr.length <= 1) return arr;
//1.找数组中间值,Mash取整,将原数组中的中间值去掉
let middleIndex = Math.floor(arr.length / 2);
let middleValue = arr.splice(middleIndex, 1);
//2.创建左右的新数组,大于中间数的放在右边,反之左边
let arrLeft = [], arrRight = [];
for (let i = 0; i < arr.length; i++) {
arr[i] < middleValue ? arrLeft.push(arr[i]) : arrRight.push(arr[i]);
}
//3.利用函数的递归,并且concat拼接数组
return quicksort(arrLeft).concat(middleValue, quicksort(arrRight));
}
2、冒泡排序
function selsetSort(arr) {
let num = 0;
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
num = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = num;
}
}
};
return arr;
}
3、选择排序
function selectSort(arr) {
for (var i = 0; i < arr.length - 1; i++) {
var index = i;
for (var j = i + 1; j < arr.length; j++) {
if (arr[index] > arr[j]) {
index = j;
}
};
if (index != i) {
var temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
};
return arr;
}
4、sort
function sortArray(n1, n2) {
return n1 - n2;
}
arr.sort(sortArray);
19.深浅拷贝
数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和对象数据类型(引用数据类型)
基本类型存储在栈(stack),引用类型在栈中存储变量名和引用地址,数据存放在堆内存里,深浅拷贝针对的是引用类型
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象指向同一地址,共享同一块内存
1、Object.assign()
var newObj = Object.assign(obj);
当obj只有单个数据,为深拷贝。第一个参数是目标对象,后面的参数是源对象,只有一个参数,直接返回该对象
2、Array.prototype.concat()
var arr1 = arr.concat();
3、Array.prototype.slice()
var arr1 = arr.slice();
Array的方法在复制的值为基础类型时,为深拷贝
深拷贝会开辟堆内存,存放新的数据
1、JSON.parse(JSON.stringify())
原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,而对象会开辟新的栈,实现深拷贝。可以实现数组或对象深拷贝,但不能处理函数function, 函数无法直接转换为字符串。
let arr1 = JSON.parse(JSON.stringify(arr));
2、递归
原理:遍历对象、数组直到里边为基本类型,再去复制,就是深度拷贝
function copy(obj) {
var newObj = null;
if (typeof (obj) == 'object' && obj !== null) {
newObj = obj instanceof Array ? [] : {};
for (let i in obj) {
newObj[i] = copy(obj[i])
}
} else {
newObj = obj
}
return newObj;
}
20.解析url
function statistics(url) {
var obj = {};
var urls = url.split('?');
var arr = urls[1].split('&');
for (var i = 0; i < arr.length; i++) {
var brr = arr[i].split('=');
obj[brr[0]] = brr[1];
}
return obj;
}
21.封装函数clone,对JS中的5种数据类型进行值复制
对象克隆支持基本数据类型及对象递归方法
function clone(obj) {
var o;
switch (typeof obj) {
case "undefined":
break;
case "string":
o = obj + "";
break;
case "number":
o = obj - 0;
break;
case "boolean":
o = obj;
break;
case "object":
// object 分为两种情况 对象(Object)或数组(Array)
if (obj === null) {
o = null;
} else {
if (Object.prototype.toString.call(obj).slice(8, -1) === "Array") {
o = [];
for (var i = 0; i <= obj.length; i++) {
o.push(clone(obj[i]));
}
} else {
o = {};
for (var k in obj) {
o[k] = clone(obj[k]);
}
}
}
break;
default:
o = obj;
break;
}
return o;
}
22.消除数组重复元素
var arr1 = [1, 2, 2, 2, 3, 3, 3, 4, 5, 6],
arr2 = [];
for (var i = 0, len = arr1.length; i < len; i++) {
if (arr2.indexOf(arr1[i]) < 0) {
arr2.push(arr1[i]);
}
}
document.write(arr2); // 1,2,3,4,5,6
23....
...