第三周总结(下)
创建对象
字面量的方式
这种方式在日常开发过程中常用到,例如:const obj ={ name:"悟空",height:100,age:5000};
,这种方式的缺点是不适合创建多个同样类型的对象的场景,优点是方便书写。
工厂模式
本质是,一种代码的复用,也是一种设计模式。以函数的形式复用了结构,这种简化获取相同结构对象的函数,叫做工厂模式。
例如:
let stu1={name:"安琪拉",gender:'女',height:168,stuId:"001"}
function createStudent(name,gender,height,stuId){
return {name,gender,height,stuId}
}
let stu2=createStudent("亚瑟","男",186,'002')
console.log(stu1,stu2)
缺点:所有东西造出来都一样,都属于Object,无法区分对象,就无法分类管理。要想区分,自定义构造函数,不同的对象来源于不同的构造函数。
构造函数
作用:①用来产生对象,调用函数时,使用new关键字;②分类对象,给不同的对象提供不同的功能和数据。
特点:
- 函数名使用大驼峰的写法;
- 添加东西,就直接使用this.属性名,然后赋值;
- 函数内部不需要return;
优点:①方便地创建了对象;②而且在对象上创建的属性,能和对象产生直接的联系;
构造函数代码举例:
// 1.声明函数
function CreateStudent(name,age){
// this就是obj
// 通过this赋值
this.name=name
this.age=age
}
// 3. 通过new创建对象
const obj=new CreateStudent('猪八戒','130')
console.log(obj)
关键字new都做了那些事情:
- 在堆中开辟一块内存;
- 创建一个新的空对象;
- 调用构造函数(为对象赋值):新对象.构造函数,构造函数的this指向对象;
- 将对象的内存地址返回到new处;
构造函数的缺点
代码:
function createStudent(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name);
}
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // false 不是同一say方法 浪费了内存
问题描述:new一次就会开辟一个新的对象内存空间,方法也就会在每个对象内存中存储一份,这就导致内存占用严重
解决方案
// 提前将say 声明好
function say() {
console.log(this.name);
}
function createStudent(name, age) {
this.name = name;
this.age = age;
this.say = say
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // true
但是,这种思路有产生了新问题,虽然解决了浪费内存的问题,但是也造成了全局污染。
创建函数
第一种,具名函数
fn();//函数声明可以先调用,在声明
function fn(参数..){
console.log("这是函数声明")
return 返回值
}
第二种,函数表达式(匿名函数)
const fn = function() {
console.log("这是函数表达式");
}
fn();//函数表达式必须先声明,再调用
第三种,构造函数的写法
const fn1 = new Function("a1", "a2", "alert(a1+a2)");
fn1(1,2);
这种写法,本人认为是最正规的写法,直接告诉使用者所有的函数都是由Function创建的。
闭包
闭包又被称为函数闭包,内部函数用到了外部函数的局部变量,这种现象就叫做闭包。
闭包的作用:
- 让数据变得更加安全;
- 函数内部返回另一个函数;
注意:
- 闭包一定是返回调用的函数,两层函数,外层放数据,内层做逻辑处理。
- 外层函数,返回内层函数,内层返回具体数据。
- 闭包只做数据加工,不做效果。
示例代码:
<h1></h1>
<button>点击</button>
<script>
// arr=[{name:"金"},{name:"木"},{name:"水"},{name:"火"},{name:"土"}]
function show(){
let arr=[{name:"金"},{name:"木"},{name:"水"},{name:"火"},{name:"土"}];
let index=-1
return ()=>{
index++
if(index>=arr.length)index=0
return arr[index].name
}
}
let data=show()
document.querySelector('h1').innerHTML=data()
document.querySelector("button").onclick=function(){
document.querySelector('h1').innerHTML=data()
}
// 外面的函数只调用一次,即能使变量没有重置,又保护了变量数据的安全
</script>
闭包的缺陷和解决方案
缺陷:占用了内存。
解决方案:将占用函数的变量释放掉,占用链断裂,垃圾回收机制立即回收。如果进行闭包释放,接收闭包函数的时候,不要const,否则不能二次赋值。使用let则可以释放。
闭包虽然有占用内存的缺陷,实际上很少释放,所以默认不允许占用内存。
递归
递归,就是函数自己调用自己。利用空间换时间,同时让N个相同的函数执行内存就会不断地被占用,
狭义递归解决问题的方式:
- 必须是函数:函数内部调用自己;
- 先解决大问题,然后通过规模变小后,再调用自己去解决小问题;
递归的两要素:
- 递归点:在函数解决问题的过程中,发现小问题(规模变小,性质一样),调用自己(参数规模减小:递归一定有参数);
- 递归出口:函数一定要能够不再调用自己,分为显示出口和隐式出口。显示出口:发现不应该调用函数自己,立马结束:return。隐式出口:函数自动运行结束,没有发现递归点。
需求:用div包裹结构里面的数据:name的数据
// data
let data=[
{
"name": "广东",
"children": [
{
"name": "广州",
"children": [
{
"name": "越秀"
},
{
"name": "天河",
"children": [
{
"name": "吉山"
}
]
}
]
},
{
"name": "深圳",
"children": [
{
"name": "南山"
}
]
}
]
}
]
不使用递归的代码:
data.forEach(function(item){
document.querySelector("body").innerHTML+=`<div>${item.name}</div>`
if(item.children){
item.children.forEach(function(item){
document.querySelector("body").innerHTML+=`<div>${item.name}</div>`
if(item.children){
item.children.forEach(function(item){
document.querySelector("body").innerHTML+=`<div>${item.name}</div>`
if(item.children){
item.children.forEach(function(item){
document.querySelector("body").innerHTML+=`<div>${item.name}</div>`
})
}
})
}
})
}
})
使用递归的代码:
function recursion_city(data){
data.forEach(function(item){
document.querySelector("body").innerHTML+=`<div>${item. name}</div>`
if(item.children){
recursion_city(item.children)
}
})
}
recursion_city(data)
jQuery
jQuery是针对DOM的操作,数据加工使用原生JS。
jQuery的使用步骤:
- 引入jQuery文件;
- 添加入口函数;
- 在入口函数中,调用封装好的API实现页面效果;
jQuery的入口文件
入口文件的作用是,等待文档中的标签加载完毕,不是等待所有内容加载完毕,然后再去执行入口函数的代码。
使用方式:
// 方式一
$(document).ready(function(){ });
// 方式二
$(function(){ })
入口文件的好处:
- 等待文档加载完成,保证能够获取到元素;
- 防止全局变量污染,所有的东西都是局部;
入口函数与window.onload的差异
执行次数方面:
- window.onload只能执行一次,如果有多个,后面的会将前面的覆盖
- jQuery的入口函数可以添加多个,而且都会执行,不存在覆盖的问题
执行时机方面:
- window.onload必须等网页所有资源,包括图片等外部资源,全部加载完毕,才会执行入口函数中的代码
- jQuery的入口函数只要页面中的DOM结构加载完毕,就会执行入口函数中的代码
简写方面:
- window.onload无法简写
- jQuery入口函数简写是:${function(){代码}}
jQuery与DOM之间的转换
- jQuery→DOM:$("div")
- DOM→jQuery:$("div").get(index)
jQuery选择器
筛选选择器
image.png筛选方法
特点就是,先拿到所有,再筛选出需要的元素
image
jQuery样式操作
- css
单样式操作:
$box.css(名字,值)
多样式操作:
$box.css({名字:值,……})
- addClass
- removeClass
- hasClass,判断类
- toggleClass,切换类,一个类的开关
jQuery动画
属性
- 显示与隐藏(默认没有动画效果)
- show()显示
- hide()隐藏
- toggle()切换
- 滑入与划出
- slideDown()滑入
- slideUp()滑出
- slideToggle()切换
- 淡入与淡出
- fadeIn()淡入
- fadeOut()淡出
- fadeTogge()切换
参数
参数1:速度,默认normal(400)
参数2:变化方式,默认曲线
参数3:回调函数,动画结束调用