call和apply和bind
call
Function.prototype.myCall = function (context = window, ...args) {
if (typeof this !== 'function') {
throw new TypeError('is not function')
}
const fn = Symbol()
// 保存执行的函数
context[fn] = this
// 执行函数,被执行的函数this指向当前内部的context对象
let res = context[fn](...args)
delete context[fn]
return res
}
apply
Function.prototype.myApply = function (context = window, args = []) {
if (typeof this !== 'function') {
throw new TypeError('is not function')
}
const fn = Symbol()
context[fn] = this
let res = context[fn](...args)
delete context[fn]
return res
}
bind
Function.prototype.myBind = function (context = window, ...args1) {
if (typeof this !== 'function') {
throw new TypeError('is not function')
}
const _this = this
return function F(...args2) {
if (this instanceof F) {
return new _this(...args1, ...args2)
} else {
// 利用闭包保存context
return _this.apply(context, [...args1, ...args2])
}
}
}
防抖和节流
防抖
function debounce(fn, wait = 50) {
let timer
return function (...args) {
// 利用闭包,如果在wait时间内重新调用,则清除上一个定时器
if (timer) clearTimeout(timer)
// 重新开一个定时器,在wait毫秒后执行FN
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
节流
function throttle(fn, wait = 50) {
let lastTime = 0
return function (...args) {
const nowTime = +new Date()
// 当前时间减去上一次时间大于设置的时间就执行
if (nowTime - lastTime >= wait) {
// 重新赋值
lastTime = nowTime
fn.apply(this, args)
}
}
}
结合版
function fff(fn, wait = 50) {
let lastTime = 0
let timer
return function (...args) {
if (nowTime - lastTime >= 50) {
clearTimeout(timer)
timer = null
lastTime = nowTime
fn.apply(this, args)
} else if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
}
深拷贝和浅拷贝
浅拷贝(值拷贝,引用类型会复制地址)
1.循环赋值
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。Object.create(proto,[propertiesObject])接收两个参数一个是新创建对象的__proto__, 一个属性列表
function clone(obj) {
let obj2 = Object.create(null)
for (const key in obj) {
obj2[key] = obj[key]
}
return obj2
}
2.扩展运算符
创建一个新的对象,并将原始对象的属性和值复制到新对象中。如果原始对象中包含了其他对象作为其属性值,那么新对象和原始对象会共享这些属性,它们都指向同一个对象。
let obj1 = { ...obj }
3.assign方法
Object.assign()用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。
let obj2 = Object.assign({},obj1)
深拷贝(重新开辟空间)
1.JSON方法(无法解决互相引用等问题)
function deepClone(obj){
return JSON.parse(JSON.stringify(obj))
}
2.递归
function isObject(obj) {
const {
toString
} = Object.prototype
return toString.call(obj) === '[object Object]' || toString.call(obj) === '[object Array]'
}
function deepClone(obj) {
if (isObject(obj)) {
let o = Array.isArray(obj) ? [] : {}
// 循环判断是不是对象,如果是对象就递归进去,普通属性直接赋值
for (const key in obj) {
if (isObject(obj[key])) {
o[key] = deepClone(obj[key])
} else {
o[key] = obj[key]
}
}
return o
} else {
return obj
}
}
对象比较
1.JSON.stringify(obj)
// todo: 判断两个对象转后的字符串是否相等
// 缺陷:当两个对比的对象中key的顺序不是完全相同时会比较出错
function shallowEqual(object1, object2) {
const obj1 = JSON.stringify(object1);
const obj2 = JSON.stringify(object2);
if (obj1.length !== obj1.length || obj1 !== obj2) {
return false;
}
return true;
}
2.逐个访问
Object.prototype.deepCompare = function (obj) {
const objKeys1 = Object.keys(this)
const objKeys2 = Object.keys(obj)
// 两个对象的属性量不同
if(objKeys1.length !== objKeys2.length){
return false
}
// 遍历objKeys1对象对比每一个属性
for(let key of objKeys1){
if(this[key] !== obj[key]){
return false
}
}
return true
}
let obj = {
a:1,
b:2
}
console.log(obj.deepCompare({a:1,b:2})) // true
数组方法
去重
1. 利用 Set
function unique (arr) {
return Array.from(new Set(arr))
}
2. 利用 indexOf
function unique(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (res.indexOf(arr[i]) === -1) {
res.push(arr[i])
}
}
return res
}
3. 利用filter
function unique(arr) {
return arr.filter((item, index, arr) =>{
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index
})
}
4. 利用reduce
function unique(arr) {
return arr.reduce((prev, current) => {
// 前置数组不包括当前元素就添加
if (!prev.includes(current)) { prev.push(current) }
return prev
}, [])
}
乱序
// 1. 利用sort方法
function random(arr) {
return arr.sort(() => .5 - Math.random())
}
// 2. 手动调换位置
function random(arr) {
let len = arr.length
let current = len - 1
while (current > -1) {
let randomNum = Math.floor(Math.random() * len);
[arr[current], arr[randomNum]] = [arr[randomNum], arr[current]]
current--
}
return arr
}
扁平化
1. 利用原生方法
const arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.flat(Infinity);
}
console.log(flatten(arr)); // [1, 2, 3, 4,5]
2. 只能解决二维数组
function flat(arr) {
let res = []
for (const i of arr) {
if (Array.isArray(i)) {
res = res.concat(flat(i))
} else {
res.push(i)
}
}
return res
}
3. 利用reduce
function flat(arr) {
return arr.reduce((pre, cur) => {
return Array.isArray(cur) ? [...pre, ...flat(cur)] : [...pre, cur]
}, [])
}
function flat(arr) {
return arr.reduce((pre, cur) => {
return Array.isArray(cur) ? pre.concat(flat(cur)) : pre.concat(cur)
}, [])
}
4. (魔法) 去掉双引号
function flat(arr) {
// 去掉双引号 得到一个"1,2,3,4,5,6"的字符串
let str = JSON.stringify(arr).replace(/(\[|\])/g, '')
return str.split(',').map(key => key - 0)
}
5. (魔法) 利用toString
const arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.toString().split(',');
}
console.log(flatten(arr)); // [1, 2, 3, 4]
模拟map
1. 利用reduce
// map的参数 current当前正在处理的元素,index索引,array,当前数组
// 返回一个新数组
Array.prototype.myMap = function (handler) {
return this.reduce((target, current, index, array) => {
target.push(handler.call(this, current, index, array))
return target
}, [])
}
2. 遍历引用的数组
Array.prototype.myMap = function (hanler) {
let res = []
// this指向调用的数组
for (let i = 0; i < this.length; i++) {
res.push(hanler(this[i], i, this))
}
return res
}
模拟filter
1. 利用reduce
// map的参数 current当前正在处理的元素,index索引,array,当前数组
// 返回过滤后的数组
Array.prototype.reduceToFilter = function (handler) {
return this.reduce((target, current, index, array) => {
// 如果满足传入的函数
if (handler.call(this, current, index, array)) {
target.push(current)
}
return target
}, [])
}
2. 遍历
Array.prototype.myFilter = function (hanler) {
let res = []
for (let i = 0; i < this.length; i++) {
if (hanler(this[i], i, this)) {
res.push(this[i])
}
}
return res
}
模拟fill
//array.fill(value, start, end)
//value 必需。填充的值。start 可选。开始填充位置。end 可选。停止填充位置 (默认为 array.length)
Array.prototype.myFill = function (target, start = 0, end = arr.length) {
for (let i = start; i < end; i++) {
this[i] = target
}
}
模拟find
// find() 方法返回数组中满足提供的测试函数的第一个元素的值。 否则返回 undefined
Array.prototype.myfind = function (fn, start = 0, end = this.length) {
for (let i = start; i < end; i++) {
if (fn.call(this, this[i], i, this)) {
return this[i]
}
}
}
模拟findIndex
// findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。 否则返回 -1
Array.prototype.myFindIndex = function (fn, start = 0, end = this.length) {
for (let i = start; i < end; i++) {
if (fn.call(this, this[i], i, this)) {
return i
}
}
return -1
}
实现 promise.all
1. async
// 用async实现promise.All
async function asyncAlls(jobs) {
try {
let results = jobs.map(async job => await job)
let res = []
for (const result of results) {
res.push(await result)
}
return res
} catch (error) {
throw new Error(error)
}
}
2. for await of
// 一秒后1,2秒后2,3秒后3,并不是并行,需要trycatch捕获错误
const asyncAll = async (promises) => {
try {
for await (item of promises) {
console.log(item);
}
} catch (e) {
console.log(e)
}
}
const a = function () {
return new Promise(resolve => {
setTimeout(() => {
resolve(1)
}, 1000);
})
}
const b = function () {
return new Promise(resolve => {
setTimeout(() => {
resolve(2)
}, 2000);
})
}
const c = function () {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(333)
}, 3000);
})
}
asyncAll([a(), b(), c()])
模拟promise
1. Typescript版
type PromiseState = 'pending' | 'resolved' | 'rejected'
interface PromiseResolve<T> {
(value: T): void
}
interface PromiseReject<T> {
(value: T): void
}
interface MyPromiseMethod<T> {
then: (onFulfilled: any, onRejected: any) => void
all: (promises: MyPromise<T>) => any
race: (promises: MyPromise<T>[]) => any
reject: (reason: any) => any
resolve: (value: any) => any
catch: (error: any) => any
finally: (fn: any) => any
}
class MyPromise<T> implements MyPromiseMethod<T> {
state: PromiseState
value: T
reason: T
successCb: PromiseResolve<T>[]
failCb: any[]
constructor(exec) {
this.state = 'pending'
this.value = null
this.reason = null
this.successCb = []
this.failCb = []
const resolve: PromiseResolve<T> = (value: T) => {
if (this.state === 'pending') {
this.value = value
this.state = 'resolved'
this.successCb.forEach((fn) => { fn(value) })
}
}
const reject: PromiseReject<T> = (reason: T) => {
if (this.state === 'pending') {
this.reason = reason
this.state = 'rejected'
this.failCb.forEach((fn) => { fn(reason) })
}
}
try {
exec(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => reason
if (this.state === 'pending') {
this.successCb.push(onFulfilled)
this.failCb.push(onRejected)
}
if (this.state === 'resolved') {
onFulfilled(this.value)
}
if (this.state === 'rejected') {
onFulfilled(this.reason)
}
}
all(promise) {
let count = 0
let res = []
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promise.length; i++) {
(promise[i] as MyPromise<T>).then(value => {
res.push(value)
count++
if (count === promise.length) {
resolve(res)
}
}, e => {
reject(e)
})
}
})
}
race(promise) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < promise.length; i++) {
(promise[i] as MyPromise<T>).then(value => {
resolve(value)
}, e => {
reject(e)
return
})
}
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
catch(onRejected) {
return this.then(null, onRejected)
}
finally(fn) {
this.then((value) => {
fn()
return value
}, err => {
fn()
return err
})
}
}
function testPromise(value) {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if (value > 5) {
resolve('大于5')
} else {
reject('小于等于5')
}
}, 50)
})
}
function testPromise2(value) {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
if (value > 5) {
resolve('大于5')
} else {
reject('小于等于5')
}
}, 50)
})
}
MyPromise.prototype
.all([testPromise2(11), testPromise(10)])
.then(value => {
console.log(value)
}, e => { console.log(e) })
2. JavaScript版
var PromisePolyfill = (function () {
// 和reject不同的是resolve需要尝试展开thenable对象
function tryToResolve (value) {
if (this === value) {
// 主要是防止下面这种情况
// let y = new Promise(res => setTimeout(res(y)))
throw TypeError('Chaining cycle detected for promise!')
}
// 根据规范2.32以及2.33 对对象或者函数尝试展开
// 保证S6之前的 polyfill 也能和ES6的原生promise混用
if (value !== null &&
(typeof value === 'object' || typeof value === 'function')) {
try {
// 这里记录这次then的值同时要被try包裹
// 主要原因是 then 可能是一个getter, 也也就是说
// 1. value.then可能报错
// 2. value.then可能产生副作用(例如多次执行可能结果不同)
var then = value.then
// 另一方面, 由于无法保证 then 确实会像预期的那样只调用一个onFullfilled / onRejected
// 所以增加了一个flag来防止resolveOrReject被多次调用
var thenAlreadyCalledOrThrow = false
if (typeof then === 'function') {
// 是thenable 那么尝试展开
// 并且在该thenable状态改变之前this对象的状态不变
then.bind(value)(
// onFullfilled
function (value2) {
if (thenAlreadyCalledOrThrow) return
thenAlreadyCalledOrThrow = true
tryToResolve.bind(this, value2)()
}.bind(this),
// onRejected
function (reason2) {
if (thenAlreadyCalledOrThrow) return
thenAlreadyCalledOrThrow = true
resolveOrReject.bind(this, 'rejected', reason2)()
}.bind(this)
)
} else {
// 拥有then 但是then不是一个函数 所以也不是thenable
resolveOrReject.bind(this, 'resolved', value)()
}
} catch (e) {
if (thenAlreadyCalledOrThrow) return
thenAlreadyCalledOrThrow = true
resolveOrReject.bind(this, 'rejected', e)()
}
} else {
// 基本类型 直接返回
resolveOrReject.bind(this, 'resolved', value)()
}
}
function resolveOrReject (status, data) {
if (this.status !== 'pending') return
this.status = status
this.data = data
if (status === 'resolved') {
for (var i = 0; i < this.resolveList.length; ++i) {
this.resolveList[i]()
}
} else {
for (i = 0; i < this.rejectList.length; ++i) {
this.rejectList[i]()
}
}
}
function Promise (executor) {
if (!(this instanceof Promise)) {
throw Error('Promise can not be called without new !')
}
if (typeof executor !== 'function') {
// 非标准 但与Chrome谷歌保持一致
throw TypeError('Promise resolver ' + executor + ' is not a function')
}
this.status = 'pending'
this.resolveList = []
this.rejectList = []
try {
executor(tryToResolve.bind(this), resolveOrReject.bind(this, 'rejected'))
} catch (e) {
resolveOrReject.bind(this, 'rejected', e)()
}
}
Promise.prototype.then = function (onFullfilled, onRejected) {
// 返回值穿透以及错误穿透, 注意错误穿透用的是throw而不是return,否则的话
// 这个then返回的promise状态将变成resolved即接下来的then中的onFullfilled
// 会被调用, 然而我们想要调用的是onRejected
if (typeof onFullfilled !== 'function') {
onFullfilled = function (data) {
return data
}
}
if (typeof onRejected !== 'function') {
onRejected = function (reason) {
throw reason
}
}
var executor = function (resolve, reject) {
setTimeout(function () {
try {
// 拿到对应的handle函数处理this.data
// 并以此为依据解析这个新的Promise
var value = this.status === 'resolved'
? onFullfilled(this.data)
: onRejected(this.data)
resolve(value)
} catch (e) {
reject(e)
}
}.bind(this))
}
// then 接受两个函数返回一个新的Promise
// then 自身的执行永远异步与onFullfilled/onRejected的执行
if (this.status !== 'pending') {
return new Promise(executor.bind(this))
} else {
// pending
return new Promise(function (resolve, reject) {
this.resolveList.push(executor.bind(this, resolve, reject))
this.rejectList.push(executor.bind(this, resolve, reject))
}.bind(this))
}
}
// for prmise A+ test
Promise.deferred = Promise.defer = function () {
var dfd = {}
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
// for prmise A+ test
if (typeof module !== 'undefined') {
module.exports = Promise
}
return Promise
})()
PromisePolyfill.all = function (promises) {
return new Promise((resolve, reject) => {
const result = []
let cnt = 0
for (let i = 0; i < promises.length; ++i) {
promises[i].then(value => {
cnt++
result[i] = value
if (cnt === promises.length) resolve(result)
}, reject)
}
})
}
PromisePolyfill.race = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; ++i) {
promises[i].then(resolve, reject)
}
})
}
模拟AJAX
function ajax(config: AjaxConfig) {
return new Promise((resolve, reject) => {
const { data = null, url, method = 'Get' } = config
const request = new XMLHttpRequest()
request.open(method, url, true)
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
resolve(request.responseText);
} else {
reject(request.statusText)
}
}
request.send(JSON.stringify(data))
})
}
new 的过程
function myNew(fn, ...args) {
//创建一个新对象,将新对象的__proto__ 指向构造函数的原型
let obj = Object.create(fn.prototype)
let res = fn.apply(obj, args)
return res instanceof Object ? res : obj
}
Object.create()
// 用于创建一个新对象,被创建的对象继承另一个对象(o)的原型
function create(obj) {
function F() { }
F.prototype = obj
return new F()
}
实现instanceof的功能
function myInstanceof(obj, F) {
while (obj.__proto__) {
if (obj.__proto__ === F.prototype) {
return true
}
obj = obj.__proto__
}
return false
}
使用setTimeout实现setInterval方法
// 取消定时器
let obj = {
flag: false
}
function mySetinterval(fn, timer = 4000, ...args) {
if (obj.flag) { return }
setTimeout(() => {
console.log(777, obj.flag)
fn(...args)
mySetinterval(fn, timer, ...args)
}, timer)
return obj
}
实现JSONP
//https://sp0.baidu.com/su?wd=Java&cb=cb'; 没有判断是否有?
function jsonP(url, data, cb) {
let script = document.createElement('script')
let str = url
if (data || cb) { str += '?' }
for (let [key, value] of Object.entries(data)) {
str += `${key}=${value}&`
}
if (cb) {
str += `${cb}=${cb}`
}
script.scr = str
document.body.appendChild(script)
}
promise 实现sleep函数
function sleep(wait = 50){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve()
}, wait)
})
}
单例模式
1.
class Person {
static instance: null | Person
private name: string
private age: string
constructor(name, age) {
this.name = name
this.age = age
}
static createPerson(name, age) {
if (!Person.instance) {
Person.instance = new Person(name, age)
}
return Person.instance
}
}
2.
class Singleton {
constructor() {}
}
Singleton.getInstance = (function() {
let instance
return function() {
if (!instance) {
instance = new Singleton()
}
return instance
}
})()
let s1 = Singleton.getInstance()
let s2 = Singleton.getInstance()
console.log(s1 === s2) // true
策略模式
// 1.HTML
<form class="cs-form">
<label>
<span>账号:</span>
<input name="account" type="text" />
</label>
<label>
<span>密码:</span>
<input name="password" type="password" />
</label>
<label>
<span>手机号:</span>
<input name="mobile" type="number" />
</label>
<button class="submit" type="submit">登录</button>
</form>
// 2. JavaScript
interface Iform {
[k: string]: any;
account: HTMLInputElement;
password: HTMLInputElement;
mobile: HTMLInputElement;
}
interface Ilist {
value: string;
type: name;
msg: string;
}
interface Iadd {
type: name;
msg: string;
}
type name = keyof typeof rule;
// 匹配规则
const rule = {
require(value: string, msg: string) {
if (!value) {
return msg;
}
},
minLength(value: string, msg: string) {
if (value.length < 6) {
return msg;
}
},
mobile(value: string, msg: string) {
if (!/\d{11}/.test(value)) {
return msg;
}
}
};
class Verification {
private list: Ilist[] = [];
public message: string;
// 用函数重载的形式实现
add<T extends { value: string }>(dom: T, type: name, msg: string): void;
add<T extends { value: string }>(dom: T, ruleArr: Array<Iadd>): void;
add<T extends { value: string }>(
dom: T,
ruleArr: Array<Iadd> | name,
msg?: string
): void {
// 如果匹配规则是数组的话,则遍历添加进去
if (Array.isArray(ruleArr)) {
this.list.push(
...ruleArr.map(f => {
return {
value: dom.value,
type: f.type,
msg: f.msg
};
})
);
} else {
this.list.push({
value: dom.value,
type: ruleArr,
msg: msg || ''
});
}
}
start(): boolean {
// 遍历执行
for (let i = 0; i < this.list.length; i++) {
const { value, type, msg } = this.list[i];
const fn = rule[type](value, msg);
if (fn) {
this.message = msg;
return false;
}
}
this.message = "";
return true;
}
}
const form = document.querySelector(".cs-form") as HTMLFormElement;
form.addEventListener("submit", function(e) {
e.preventDefault();
const { account, password, mobile } = (form as unknown) as Iform;
const ruleSet = new Verification();
// 添加规则
ruleSet.add(account, "require", "请输入账号");
ruleSet.add(password, [
{
type: "require",
msg: "请输入密码"
},
{
type: "minLength",
msg: "密码长度不符合要求"
}
]);
ruleSet.add(mobile, [
{
type: "require",
msg: "请输入手机号"
},
{
type: "mobile",
msg: "请输入正确的手机号"
}
]);
if (!ruleSet.start()) {
// 提示
alert(ruleSet.message);
return false;
}
return false;
});
发布订阅模式
class Watcher {
constructor() {
this.subs = []
}
on(eventName, fn) {
if (this.subs[eventName]) {
this.subs[eventName].push(fn)
} else {
this.subs[eventName] = [fn]
}
}
emit(eventName, ...args) {
if (Array.isArray(this.subs[eventName])) {
this.subs[eventName].forEach(fn => {
fn.apply(this, args)
})
}
}
unbind(eventName, fn) {
if (fn) {
this.subs[eventName] = this.subs[eventName].filter((e) => e !== fn && e.orgin !== fn)
} else {
delete this.subs[eventName]
}
}
once(eventName, fn) {
let only = (...args) => {
fn.apply(this, args)
this.unbind(eventName, fn)
}
only.orgin = fn
this.on(eventName, only)
}
}
函数柯里化
// 手写一个简单的把普通函数变为柯里化函数的方式
// 每次调用的传进来的参数做累计处理
function reduce (...args) {
return args.reduce((a, b) => a + b);
}
function currying (fn) {
// 存放每次调用的参数
let args = [];
return function temp (...newArgs) {
if (newArgs.length) {
// 有参数就合并进去,然后返回自身
args = [ ...args, ...newArgs ];
return temp;
} else {
// 没有参数了,也就是最后一个了,执行累计结果操作并返回结果
let val = fn.apply(this, args);
args = [] //保证再次调用时清空
return val;
}
}
}
let add = currying(reduce);
console.log(add(1)(2, 3, 4)(5)()); //15
console.log(add(1)(2, 3)(4, 5)()); //15
异步循环打印
1.利用let限制作用域
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 0)
}
2. 利用闭包保存变量
(function (j) {
setTimeout(() => {
console.log(j)
}, 0)
})(i)
3. 利用定时器的第三个参数
// 第三个参数会被当成第一个函数的参数
for (var i = 0; i < 10; i++) {
setTimeout((j) => {
console.log(j)
}, 0, i)
}
实现继承
1. class
class Father {
constructor(name) {
this.name = name
}
sayHi() {
console.log(`${this.name} Say Hi`)
}
}
// 会自动继承父类的原型
class Son extends Father {
constructor(name, age) {
//使用super调用父类构造函数
super(name)
this.age = age
}
}
const person = new Son('zs', 15)
person.sayHi()
2. 原型链继承
`缺点 1.创建子类实例时,无法向父类构造函数传参 2.共享父类引用类型对象`
function Father() {
this.arr = [1,2,3,4,5]
}
Father.prototype.sayHi = function () {
return `说 Hi`
}
function Son(age) {
this.age = age
}
Son.prototype = new Father()
const son = new Son(15)
const son2 = new Son(15)
son.arr.push(6)
son.arr === son2.arr //true
3. 构造函数继承
`缺点 1.无法继承父类的原型`
function Father(name) {
this.name = name
}
Father.prototype.sayHi = function () {
return `说 Hi`
}
function Son(name, age) {
Father.call(this, name)
this.age = age
}
const son = new Son('zs',15)
4. 组合继承
`缺点 1.调用两次构造函数,浪费内存`
function Father(name) {
this.name = name
}
Father.prototype.sayHi = function () {
return `${this.name} 说 Hi`
}
function Son(name, age) {
Father.call(this, name)
this.age = age
}
Son.prototype = new Father()
const son = new Son('zs', 15)
5. 寄生式继承
function Father(name) {
this.name = name
}
Father.prototype.sayHi = function () {
return `${this.name} 说 Hi`
}
function Son(name, age) {
Father.call(this, name)
this.age = age
}
Son.prototype = Object.create(Father.prototype, {
constructor: {
value: Son
}
})
const son = new Son('zs', 15)
6. 寄生组合式继承
function Father(){
this.a = [1,2]
}
father.prototype.say = function(){
console.log('aaa')
}
function Son(){
Father.call(this)
this.b = 2
}
Son.prototype = Object.create(Father.prototype)
Son.prototype.constructor = Son
const test = new Son()
插入大量DOM
let container = document.querySelector('.container')
const sum = 1000
const num = 20
const loop = Math.floor(sum / num)
let count = 0
function render() {
const frag = document.createDocumentFragment()
for (let i = 0; i < num; i++) {
const div = document.createElement('div')
div.innerHTML = `${Math.floor(count*Math.random())}`
frag.appendChild(div)
}
container.appendChild(frag)
if (++count !== loop) {
looper()
}
}
function looper(fn) {
requestAnimationFrame(fn)
}
looper(render)