如何判断一个对象是否是数组:它是否拥有数组的共有属性(push、pop等
闭包的作用
- 一个函数引用了其外部的自由变量,这就是闭包
解构赋值
ES6语法,通过匹配进行变量声明,可以将数组中的值或者对象的属性取出,赋值给其它变量
常见用法:
js封装API
实现 jQuery 中的 addClass,有三种写法
<div class="red"></div>
<div class="red"></div>
<div class="red"></div>
<div class="red"></div>
<div class="red"></div>
<div class="red"></div>
假设函数中有几个相同class的 div
- 用闭包方式封装:
function jQuery(selector){
const labelFakeArray = document.querySelectorAll(selector) //把传进来的对象变成一个伪数组
const labelArray = Array.from(labelFakeArray) //把伪数组变成一个真数组
const api = {
addClass(className){
labelArray.forEach($node => {
$node.classList.add(className)
})
},
removeClass(className){
labelArray.forEach($node => {
$node.classList.remove(className)
})
}
}
return api //调用函数,返回可操作元素的api
}
const $ = jQuery //把函数赋值给$
$('red').addClass('green') //使用函数给元素添加 class 'green'
缺点是每次调用都要再新const一个 api,耗内存
- 用构造函数方法封装
function jQuery(selector){
const fake_labelArray = document.querySelectorAll(selector)
this.labelArray = Array.from(fake_labelArray)
}
jQuery.prototype = {
constructor: jQuery,
addClass(className){
this.labelArray.forEach($node => {
$node.classList.add(className)
})
},
removeClass(className){
this.labelArray.forEach($node => {
$node.classList.remove(className)
})
}
}
const $ = jQuery
new $('red').addClass('green') //每次调用都要 new 一下
- 用 class 方法封装
class jQuery{
constructor(selector){
this.fake_labelArray = document.querySelectorAll(selector)
this.labelArray = Array.from(this.fake_labelArray)
}
addClass(className){
const { labelArray } = this
labelArray.forEach($node => {
$node.classList.add(className)
})
}
removeClass(className){
this.labelArray.forEach($node => {
$node.classList.remove(className)
})
}
}
const $ = jQuery
new $('red').addClass('green')
class 和 构造函数方法都要新 new 一下
- 在构造函数方法中如何不用 new 也可以调用api
function jQuery(selector){
if(!(this instanceof jQuery)){ //在前置中添加一个判断,如果 this 不属于jQuery,则帮用户返回 new
return new jQuery(selector)
}
const fake_labelArray = document.querySelectorAll(selector)
this.labelArray = Array.from(fake_labelArray)
}
jQuery.prototype = {
constructor: jQuery,
addClass(className){
this.labelArray.forEach($node => {
$node.classList.add(className)
})
},
removeClass(className){
this.labelArray.forEach($node => {
$node.classList.remove(className)
})
}
}
链式调用
连续执行两个或多个操作
以上面封装的api为例,在给div添加class green 之后,再添加一个 blue
可以通过给 api 添加 this,再链式调用来实现
addClass(className){
this.labelArray.forEach($node => {
$node.classList.add(className)
})
return this
},
removeClass(className){
this.labelArray.forEach($node => {
$node.classList.remove(className)
})
return this
}
- 如何确定 this 的值?
- 查看 MDN 文档
- 查看浏览器源码
- 查看函数调用 (不能看函数声明)
函数的五种调用方式
- fn (参数)
//这个方法的this是window,严格模式下是undefined
- obj.method(参数)
//this是method前面的对象,这里是obj,如果是obj.x.methos,则this是obj.x
- fn.call(this, 参数1) //给函数指定 this
- fn.apply(this, [参数1]) //给函数指定 this
- new Fn(参数) //new会在调用过程中把this指向新构建的对象
call 和 apply 会把传进来的 this 转化为对象
- 浏览器全局作用域中,非严格模式下
this = window,name = ""
箭头函数不支持 this
- 箭头函数不支持 this,箭头函数中的 this 是 window
- 在箭头函数中,this 和 a, b, c 这样的普通变量一样
- 即使用 call 给箭头函数传值,也不支持this
- 箭头函数不支持用 new 调用
函数重载
即同名不同参,接受不同数据类型的参数
如 (redList) 接受元素数组(伪),$(red)接受单个元素
只需要学会使用 if else 和 instanceof
function jQuery(selector) {
if (!(this instanceof jQuery)) {
return new jQuery(selector)
}
if (typeof selector === 'string') { //判断参数是否属于 string
const fake_labelArray = document.querySelectorAll(selector)
this.labelArray = Array.from(fake_labelArray)
}else if(selector instanceof Element) { //判断参数是否属于元素
this.labelArray = [selector]
}else { //上面都不属于,则是元素伪数组
this.labelArray = Array.from(selector)
}
}
如何接受不同长度的参数
如,('.red', div) 在某个 div 里查找 .red
用 if else,配合 arguments.length 实现
<div class="red"></div>
<div class="red" id="ccc">
<div class="red"></div>
<div class="red"></div>
<div class="red"></div>
</div>
<div class="red"></div>
<div class="red"></div>
<script>
function jQuery(selector, range) {
console.log(jQuery.length);
if (!(this instanceof jQuery)) {
return new jQuery(selector, range)
}
let fake_labelArray = arguments.length === 2 ? //判断是否传入了两个参数
range.querySelectorAll(selector) : //是,则在range内选取selector
document.querySelectorAll(selector) //不是,则在页面选取selector
this.labelArray = Array.from(fake_labelArray)
}
let ccc = document.querySelector('#ccc')
$('.red', ccc).addClass('gu')
</script>
- arguments 是函数实际传入的参数,上面代码用 arguments.length 判断是否传入了两个参数,如果是则在传入的 range 内选取 selector,不是则在全局范围内选取 selector
- 也可以通过 range 是否为 undefined 来判断
let fake_labelArray = range === undefined ?
range.querySelectorAll(selector) :
document.querySelectorAll(selector)
- argument是函数传入的实参,
- jQuery(函数名).length 则为函数的形参长度