目录
函数式VS面向对象
函数式编程改良->面向对象式编程
这是函数式
let name = '荷叶饭'
let grade = [
{ name: 'js', score: 99 },
{ name: 'docker', score: 96 }
]
function average(grade, name) {
let total = grade.reduce((last, next) => last + next.score, 0)
return `${name}的平均成绩是:${total / grade.length}`
}
console.log(average(grade,name))//荷叶饭的平均成绩是:97.5
这是面向对象式:
let user = {
name: '荷叶饭',
grade: [
{ name: 'js', score: 99 },
{ name: 'docker', score: 96 }
],
average() {//省去参数的传递
let total = this.grade.reduce((last, next) => last + next.score, 0)//直接使用this指针
return `${this.name}的平均成绩是:${total / this.grade.length}`
}
}
console.log(user.average())//荷叶饭的平均成绩是:97.5
减少意大利面条式的编程结果
属性的基本操作
增删改查
查
【.】和【[]】两种方式访问属性,属性名是个字符串的时候可以用【[]】中括号:
let user={
name:'荷叶饭',
'my age':19
}
console.log(user['my age'])//19
用【.】更普遍
增、改
对已有的就是改,对没有的就是添加
let hd={}
hd.name='后盾人'
hd['age']=18
console.log(hd.age)//18
hd.age=199
console.log(hd.age)//199
删
delete删除:
let hd={}
hd.name='后盾人'
hd['age']=18
console.log(hd.age)//18
hd.age=199
console.log(hd.age)//199
delete(hd.age)//删除
console.log(hd.age)//undefined
对象的引用传址
在js里数组和对象等都为引用类型,而深浅拷贝只适用于引用类型的数据,在值类型的数据里不作深浅拷贝的区分
深浅拷贝
深浅拷贝、传值传址写在这里
浅拷贝的几种方式:展开语法、assign、普通赋值
深拷贝:递归
const obj = {
uname: '荷叶饭',
age: 18,
friends: {
EPI: '励志轩'
},
hobby: ['乒乓球', '羽毛球']
}
const o = {}
function deepCopy(newObj, oldObj) {
for (let k in oldObj) {
if (oldObj[k] instanceof Array) {
//如果是数组
//数组本身也属于对象,所以一定把筛选数组的if写在前面
newObj[k] = []
deepCopy(newObj[k], oldObj[k])
} else if (oldObj[k] instanceof Object) {
//如果是对象
newObj[k] = []
deepCopy(newObj[k], oldObj[k])
} else {
//值类型情况
newObj[k] = oldObj[k]
}
}
}
deepCopy(o, obj)
console.log(o)
o.age = 20
o.hobby[0] = '游泳'
o.friends.EPI = '荷月'
console.log(obj)
展开语法在对象里的使用
使用展开语法合并参数:
let user = {
name: '荷叶饭',
'my age': 19
}
let hd={...user,gender:'女'}
console.log(hd)//{name: '荷叶饭', my age: 19, gender: '女'}
在函数里使用对象的展开语法:
function upload(p){
let config={
type:'*.jpeg,*.png',
size:10000//默认属性
}
config={...config,...p}//同属性名,后面的会覆盖前面的
console.log(config)//{type: '*.gif', size: 99}
}
upload({type:'*.gif',size:99})//用户传入自己的属性
对象解构
展开语法是对对象或数组的批量处理,解构是对对象或数组结构的批量处理
let user = { name: "荷叶饭", age: 19 }
// console.log(user);
//const { name:name, age:age } = user//如果新属性名和旧属性名一样
const { name, age } = user//可以简写成这样
console.log(age)//19
函数的返回值是对象,也可以使用解构语句:
function hd(){
return { name: "荷叶饭", age: 19 }
}
let {name,age}=hd()
console.log(name,age)//荷叶饭,19
函数传参的时候也可以这么写:
function user({name,age}) {
console.log(name,age)
}
user({ name: "荷叶饭", age: 19 })//荷叶饭,19
严格模式里解构的差异
严格模式要写声明语句:let或const都行,反正得写:
"use strict";
const { name, age } = { name: "向军", age: 23 };
console.log(name, age);
在普通模式下,如果变量没有被显式声明,JavaScript 会隐式地将其声明为全局变量。因此,在普通模式下,name
和 age
会被隐式声明为全局变量,代码不会报错。
不加括号时,JavaScript 会将 { ... }
解析为一个代码块,而不是对象解构赋值
({ name, age } = { name: "向军", age: 23 })//严格模式报错,得加括号
console.log(name, age);
解构操作的简写形式与变量解构
参数一样可以简写,前面说过了:
let web = { name: "后盾人", url: "houdunren.com" };
let { name, url } = web;
console.log(name, url);
数组里的变量解构如果只想取一个值,得空着:
let arr = ["后盾人", "houdunren.com"]
let [, b] = arr//不需要前面的参数可以不写
console.log(b)//houdunren.com
对象因为是以键值对存储的,所以如果键名一样可以只写要的属性:
let web = { name: "后盾人", url: "houdunren.com" };
let { url } = web;
console.log(url);
对普通变量也可以这么用:
let name = "后盾人",
url = "houdunren.com";
// console.log({ name:name, url:url })简写的本质
let opt = { name, url }
console.log(opt)//{name: '后盾人', url: 'houdunren.com'}
多层嵌套也可以用
let hd = {
name: "后盾人",
lesson: {
title: "javascript"
}
};
let {
name,
lesson: { title }
} = hd;
console.log(name, title);
解构的默认值
数组里接收的参数比较多可以给多的那个添加默认值:
let arr = ["后盾人", "houdunren.com"];
let [a, b, c = "hdcms"] = arr;//当第三个参数可能没有的时候,给他个默认值
console.log(a, b, c);//后盾人 houdunren.com hdcms
对象也可以用过:
let user = { name: "后盾人", url: "houdunren.com"};
let { url, name, title = "hdcms" } = user;
console.log(name, url, title)//后盾人 houdunren.com hdcms
let user = { name: "后盾人", url: "houdunren.com", title: "开源系统" };
let { url, name, title = "hdcms" } = user;
console.log(name, url, title)//后盾人 houdunren.com 开源系统
解构可以合并参数
那已有的参数合并给变量opt:
function createElement(opt={}){//opt默认值为{}
let {width=200,height=100,backgroundColor='red'}=opt
console.log(width,height,backgroundColor)
}
createElement()//200 100 'red'
实操一下:
function createElement(options = {}) {
let { width = 200, height = 100, backgroundColor = "red" } = options;
// console.log(width, height, backgroundColor);
const div = document.createElement("div");
div.style.width = width + "px";
div.style.height = height + "px";
div.style.backgroundColor = backgroundColor;
document.body.appendChild(div);
}
createElement({ width: 60, height: 30, backgroundColor: "green" });
如果自己不写参数,就是用默认值:
function createElement(options = {}) {
let { width = 200, height = 100, backgroundColor = "red" } = options;
// console.log(width, height, backgroundColor);
const div = document.createElement("div");
div.style.width = width + "px";
div.style.height = height + "px";
div.style.backgroundColor = backgroundColor;
document.body.appendChild(div);
}
createElement({ width: 60});
解构作为函数参数的使用
解构就是结构相似就能承载:
function hd(name, { sex, age }) {
console.log(name, sex, age);
}
hd("向军", { sex: "男", age: 18 });
对象的属性检测
孩子们原型对象和对象原型还在追我
对象与原型链属性检测实例:
一个属性可能一个对象有,像这样:
let hd = { name: "后盾人" };
let arr = ["houdunren.com", "hdcms"];
console.log(arr.hasOwnProperty("length"));//true,arr实例对象里有length属性
console.log(arr.hasOwnProperty("concat"));//false,arr实例对象没有concat属性
如果想看他的原型链上有没有,可以这么写:
console.log("concat" in arr);//true,在父级找到
console.log("length" in arr);//true,在本级找到
let a = {
name: "后盾人"
};
let b = {
url: "houdunren.com"
};
Object.setPrototypeOf(a, b);//设置b为a的原型对象
console.log(a);
console.log(a.hasOwnProperty("url"));//a里面是否包含url,a不包含,a的父级包含,所以为false
console.log("url" in a);//a的父亲包含,true
一个检测配置的demo:
function oss(options) {
if (!options.hasOwnProperty("host")) {
throw new Error("必须设置主机地址");
}
}
oss({ user: "admin" });
计算属性与assign使用
这里的 name
是一个变量,其值为 "title"
,因此 hd[name]
等价于 hd["title"]
。
let hd = {};
let name = "title";
hd[name] = "后盾人";
console.log(hd.title);//后盾人
assign合并两个对象:
const lessons = [
{
title: "媒体查询响应式布局",
category: "css"
},
{
title: "FLEX 弹性盒模型",
category: "css"
},
{
title: "MYSQL多表查询随意操作",
category: "mysql"
}
];
let res = lessons.reduce((obj, cur, index) => {
obj[`${cur["category"]}-${index + 1}`] = cur;
return obj;
}, {});
// console.log(res);
console.log(JSON.stringify(res, null, 2));
// let hd = Object.assign({ a: 1 }, { b: 2 });
// console.log(hd);
// jQuery.extend() lodash
function upload(params) {
let options = {
size: 19999
};
options = Object.assign(options, params);//合并两个对象
console.log(JSON.stringify(options, null, 2));
}
upload({ size: 99, type: "jpeg" });
遍历与dom操作
for in循环:
let hd = {
name: "后盾人",
year: "2010"
};
for (const key in hd) {
console.log(hd[key]);
}
key就是键名,hd[key]就是值
for of不行,for of操作的是可迭代对象,这种对象迭代不了
for (const iterator of hd) {
console.log(iterator);
}
会报错
但是键名可以迭代:
for (const iterator of Object.values(hd)) {
console.log(iterator);
}
entries也可以迭代:
for (const iterator of Object.entries(hd)) {
console.log(iterator);
}
可以发现返回的是个数组
可以借助这个做节点操作:
let lessons = [
{ name: "js", click: 999 },
{ name: "node", click: 127 }
];
let ul = document.createElement("ul");
for (const lesson of lessons) {
let li = document.createElement("li");
li.innerHTML = `课程:${lesson.name},点击数:${lesson.click}`;
ul.appendChild(li);
}
document.body.appendChild(ul);
三小时的课我与你势不两立
工厂函数创建对象
工厂函数是一个普通函数,它通过返回一个对象来创建实例。工厂函数不需要使用 new
关键字。
function user(name){
return {
name,
show:function(){
console.log(this.name+`-孩子们今天是除夕`)
}
}
}
let hyf=user('荷叶饭')
hyf.show()
let lzx=user('励志轩')
lzx.show()
如果想变动的话,变动工厂函数,这两个对象也会随之改变:
function user(name){
return {
name,
show:function(){
console.log(this.name+`-孩子们今天是除夕,我还在学js,这辈子有了`)
}
}
}
let hyf=user('荷叶饭')
hyf.show()
let lzx=user('励志轩')
lzx.show()
构造函数创建对象
构造函数是 JavaScript 中一种传统的创建对象的方式。它通过 new
关键字调用,并返回一个新的对象。
命名大驼峰
function User(name){
this.name=name
this.show=function(){
console.log(this.name)
}
//return this,这里return this可以省略,但是这里的return会决定使用构造函数创建的对象
}
let hyf=new User('荷叶饭')
console.log(hyf)
还有一个历史遗留的问题:当你把构造函数当一个普通函数调用的时候,this指向window,调用的属性或方法也可能调成window的属性和方法
在这种情况下使用严格模式,会报undefined,因为严格模式怕你无意识修改window的属性
数据也可以拿构造函数构建,他们的constructor指向的是他们的构造函数,js万物皆对象,皆有构造函数:
let s = new String("houdunren");
let n = new Number(1);
let o = new Object();
let b = new Boolean(true);
还有正则表达式、日期对象、函数也可以拿构造函数创建
let User = new Function(
"name",
`
this.name = name;
this.show = function(){
console.log(this.name+'是能过构造函数Function创建的');
}
`
);
let xj = new User("函数");
xj.show();
太长了,分两篇写