全文总计:12800字(含代码示例),纯文本约为8600字预计阅读时间约为20分钟,实践加理解约为1小时,感谢阅读
比如:制作计算面积的方式:函数中的this关键词代表所在的对象
就相当于:就像预约上门核酸检测做完了之后然后送走
简单来说就是:把area函数放到r1对象里面运行完后就送走(删除)
<script>
var r1 = {
width: 10,
length: 20,
};
// 制作计算面积的方式:函数中的this关键词代表所在的对象
function area() {
return this.width * this.length;
}
// 就像预约上门核酸检测做完了之后然后送走
// 把area函数放到r1对象里面运行完后就送走(删除)
r1.area=area
// 函数存入对象
console.log(r1.area());
// 调用
delete r1.area
// 删除,清理
console.log('r1:',r1);
script>
同样的套路:计算r2的面积
示意图
所有我们可以使用call来实现
var r2 = {
width: 100,
height: 20,
};
function area() {
return this.width * this.length;
}
r2.area = area;
console.log(r1.area());
delete r2.area;
// call:短暂拜访
console.log(area);
// 原型里面的call属性
// area短暂拜访r2对象
// 先到r2里面,执行完毕之后再离开
console.log(area.call(r2));
<script>
var emp = {
ename: "qiushan",
money: 10000,
};
// 发工资
function patOff(salary) {
return this.money + salary;
}
// 财务人员携带工资短暂访问emp,则为
payOff.call(emp, 20000);
</script>
短暂访问且带参数
则传参方式为
obj = { x: 100 };
function add(y, z) {
console.log('y:',y);
this.x + y + z;
}
// 短暂访问add,历史放到obj里面携带两个参数
add.call(obj,100,200);
console.log(obj);
作于于call的方法大同小异,都是让函数短暂访问对象
对照图我们发现两个参数的使用方式和作用是一样的
那这两个有区别嘛?
我们新建一个计算体积的方法,运算结果如图
我们发现不能直接传参,那我们试试其他的
数组
使用字符串时报错的
在ES6之前apply是重量级的一个api,它可以实现让不支持数组做实参的函数支持数组
例如希望把n2里面的值添加到n1数组的末尾
var n1=[11,22,33]
var n2=[23,34,35]
// 希望把n2里面的值添加到n1数组的末尾
// 调用原型里面的push的方法
n1.push(88,99)
console.log(n1);
然后再试试把n2加入n1
var n1=[11,22,33]
var n2=[23,34,35]
// 希望把n2里面的值添加到n1数组的末尾
// 调用原型里面的push的方法
n1.push(88,99)
console.log(n1);
// 把n2加入到n1里面
n1.push(n2)
console.log(n1);
结果却变了
所以需要apply方法来实现
所以只能使用apply
到原型里面找到push方法,然后云apply调用
临时放在n1数组里面执行,参数是n2数组
ES6提供了’...
'运算符,成为展开符
可以去掉外面的中括号
效果如下图
还可以这样写:
// ES6提供了'...'运算符,成为展开符
// 可以去掉外面的中括号
var n1=[11,22,33]
var n2=[44,55]
var n3=[...n1,44,...n2]
console.log(n3);
效果:
还可以配合Math.max
求最大值
Math.max
求最大值*var n1 = [11, 22, 33];
var n2 = [44, 55];
var n3 = [...n1, 44, ...n2];
console.log(n3);
console.log(Math.max(11, 22, 33, 44, 555));
console.log(Math.max(...n1));
结果如下:
bind :
以上门核酸为例
call和apply:立刻就回来—立刻触发
bind是属于预约型的—非即时触发
比如
var r1 = {
width: 10,
length: 20,
};
function volume(height) {
return this.width * this.length * height;
}
// 先登记
// 类似于:xx日期给xx做核酸
var b = volume.bind(r1, 50);
// 需要触发函数才会去调用
console.log(b());
// 所以可以用定时器来延迟触发
setTimeout(function () {
console.log(b());
}, 3000);
最基本的就是 :函数()
在那个对象里执行其中的this
就代表那个对象
其他:这三种方案都可以手动指定 函数中的this指向关键词是那个对象
...
是展开符,不仅能展开数组,也能展开对象
我们来猜猜运算结果
后写的覆盖先写的
<script>
// ES6增强语法,允许给形参添加默认值
function show(boy = "默认值") {
console.log("boy:", boy);
}
show();
show("hello");
</script>
这是一个代替arguments的语法
arguments有两个缺点:
缺点一:隐式的
;
缺点2:为数组,只能用for...of遍历
...
是个**很灵活的运算符,会因为使用场景,而变更用途
形参前书写,成为 剩余参数 **
结果如下
最主要参数属性是字符串
形式的
可以更方便使用
var a = suibian.reduce((sum, value) => sum + value, 0);
console.log(a);
剩余:把没有形参接收的实参,存储在剩余参数的数组里面
var names = ["ashan", "beibei", "master"];
// 把数组的值放在变量里面
var a = names[0];
var b = names[1];
var c = names[2];
console.log(a, b, c);
ES6的解构语法
// ES6的解构语法
var [a, b, c] = names;
console.log(a, b, c);
// 部分解构
var [x, ,y] = names
console.log(x,y);
互换
变量的值var m=10
var n=20
// 互换m和n的值
互换
变量的值原理:先把值组合为数组然后用解构语法去解构(结构的值直接写入,实现对调,因为他们在运行之前,数据都会暂存,否则会报错,在互换完后数据才会生效,从而不会产生数据错误)
var emp = {
ename: "秋山",
age: 19,
phone: "189xxxxx123",
};
// 旧的写法
var ename = emp.ename;
var age = emp.age;
var phone = emp.phone;
console.log(ename, age, phone);
var emp = {
ename: "秋山",
age: 19,
phone: "189xxxxx123",
};
// 新的写法
var {ename, age, phone} =emp
console.log(ename, age, phone);
像上面的数组结构一样只不过把中括号换成了花括号
var stu = { sname: "shanhai", age: 18, phone: 12345678901 };
方法:
var{sname,age,phone}=stu
console.log(sname, age, phone);
效果:
好处,相当于不用重新复写前面声明的数据,使之数据都能用
var r1 = {
length: 40,
width: 40,
height: 40,
};
// 传参方式
function volume(cube) {
var { length, width, height } = cube;
return length * width * height;
}
console.log(volume(r1));
用解构语法结构出长宽高,然后返回
计算的结果
同上创建方法
// 计算表面积
function area(){
var { width, height,length}=r1
return (width * height+width*length+length*height)*2
}
但是这样写太长了所以我们就可以用起别名简化一下
// 计算表面积
function area() {
var { width:w, height:h, length:l } = r1;
return (w * h + w * l + l * h) * 2;
}
console.log(area(r1));
但是这样还是太长了还可以简化一下
因为传参过来之后再取函数里面解析的,中间多了一道工序(赋值,然后解析),所以我们其实可以直接再传参的时候进行解析
所以代码可以写为
// 计算表面积
function area({ width: w, height: h, length: l }) {
return (w * h + w * l + l * h) * 2;
}
console.log(area(r1));
当然实战中也可以写
var r2={x:12,y:32}
function add({x,y}){
return x+y
}
console.log(add(r2));
上面说了简单的解构,但是再实际开发中,从后端传过来的数据,一般特别的复杂,所以需要解析的话就会很复杂例如:
var emp={
ename:"秋山",
age:18,
skill:['html', 'css', 'js','bootstrap','ajax'],
desc:{
phone:'153xxxx1211',
married:false
}
}
结构书写
数据里面的字符串也可以解构
class:班级/类
来自ES6提供了,新的面向对象的语法
前因:来自Java的语法,JS诞生是考虑过是否要引进JAVA的语法,但是后来作者认为:做一个小而精的语言,放弃了引进复杂的class语法,大量的Java程序员进入到了JS的开发行列–此时最终再 2015年加入了class语法
后果:后来由于JS的土著程序员排斥class语法,更喜欢旧的function语法,所以class目前还没有流行起来…可能以后会好起来
语法差异就只能靠背了…
var emp = {
ename: "qiushan",
age: 18,
phone: "1234567",
};
console.log(emp);
console.log(emp.ename, emp.age, emp.phone);
class语法,class类: 一类事物
class emp2{
static ename="qiushan"
static age=32
static phone=1234567
}
console.log(emp2);
console.log(emp2.age, emp2.age, emp2.phone);
我们还会发现
语法和Java貌似是大同小异
的…
但是通过打印却可以发现class的声明就是个函数,只不过是一套语法糖,从外观上模拟Java的class语法
,本质上还是JS的function
构造函数:一种特殊功能的函数,用于创建对象类型,一般搭配new运算符来使用
原型:共享的方法主要存放在,构造函数的原型,prototype里面
function Rec(width, length) {
this.width = width;
this.length = length;
}
Rec.prototype.area=function(){
return this.width*this.length
}
Rec.prototype.zc=function(){
return (this.width+this.length)*2
}
var r1=new Rec(10,5);
console.log(r1);
console.log(r1.area());
console.log(r1.zc());
观察系统的对象,原型中的方法与我们的区别
我们发现系统提供的是灰色的(不可修改)我们的却是深色的,所以来说不安全
所以我们想要安全的话就可以使用原型来实现
简单来说
系统提供的原型中的方法:权限全关,安全可靠---只能用不能改
代码可以写为
Object.defineProperties(r1, {
area:{
// value:function(){
// return this.width*this.length
// }
// 简写就是
value(){
return this.width*this.length
}
// value设置的默认值是不可被写入和修改的
},
}
再次查看发现就和系统提供的一样了
<script>
// 构造函数:一种特殊功能的函数,用于创建对象类型,一般搭配new运算符来使用
// 原型:共享的方法主要存放在,构造函数的原型,prototype里面
class Rec {
// constructor构造方法,固定的方法名称
// new运算符会自动触发此方法 new Rec(宽度,高度)
constructor(width, length) {
this.width = width;
this.length = length;
}
area() {
return this.width * this.length;
}
}
var r1 = new Rec(10, 5);
console.log(r1);
script>
我们会发现area属性会自动设置(安全,不可修改)
<script>
class Cube {
// 制作方法
constructor(width, length, height) {
this.width = width;
this.height = height;
this.length = length;
}
// 制作构造函数
area() {
return this.width * this.height * this.length;
}
zc() {
// 解构
let { width: w, height: h, length: l } = this;
return (w + h + l) * 4;
}
volume() {
return (
(this.width * this.height +
this.width * this.length +
this.length * this.width) *
2
);
}
}
// 使用
var r1 = new Cube(10, 5, 20);
// 体积
console.log(r1.volume());
// 周长
console.log(r1.zc());
// 面积
console.log(r1.area());
script>
面向对象有三大特征
{ }
把一堆代码封装起来,形成一个整体,反复使用var a={
ename: 'document',
age:19
}
把别的对象的内容给当前对象用:--原型链 对象的__proto__
方法和重写有关系,具体看看代码
<script>
// 继承
// 面向对象有三大特征
// - 封装:用{}把一堆代码封装起来,形成一个整体,反复使用
// - 继承:把别的对象的内容给当前对象用:--原型链 对象的__proto__
// - 多态:方法和重写有关系,具体看看代码
class qiushan {
eat() {
console.log("唱");
}
rep() {
console.log("rep");
}
play() {
console.log("篮球");
}
}
class beibei extends qiushan {}
var s1 = new beibei();
console.log(s1);
</script>
查看代码的原型
我们会发现beibei的原型具有秋山的eat,he,play
我们可以调用一下试试
结果为
当我们为beibei添加一个和qiushan一样的原型之后
我们发现beibei有了自己的eat属性,使用时就会按照就近原则来使用故而为
写了继承之后,则原型是指定的对象,就可以使用此对象沂源县中的方法,相当于现实中的子承父业在这里就是beibei继承qiushan的原型,当自己又是就会按照就近原则优先使用自己的,在java里面称之为重写,而当自己没有时,就会取qiushan(父亲)的原型里面去找
如果我们在函数里进行双重调用的话
就会出现:
加粗样式
产生循环然后报错
多态:父元素的代码没有修改但是由于子元素的重写,导致运行时出现不同的状态就成为多态
<script>
class Father {
show() {
console.log("我是父元素的show");
}
}
class son extends Father {
show() {
console.log("我是子元素的show");
}
}
class Father {
show() {
console.log("我是父元素的show");
}
}
class son extends Father {
show() {
console.log("我是子元素的show");
}
}
// 在使用时
var s1=new son()
s1.show()
script>
不出意料的显示了
则:如果子类中重写了show方法,则有限调用自身的元素
但是我们要使用父元素的元素
呢?
就可以用super关键词则可以写为:
就可以显示出父元素的属性啦
函数触发方式:3种可以主动修改this指向的方案
call(暂时访问):版函数临时房贷对象中执行,执行完后会删除
apply(短暂访问)—实参用数组进行传递
展开语法:…
解构语法
函数增强语法
class语法
class 类名{
static 属性 = 值
// 静态属性
constructor(形参,形参...){
this.属性 = 参数
}
xx(){}
}
封装-继承-多态