面向对象:
面向过程 POP:
分析解决问题的步骤,然后用函数把这些步骤一步一步的实现,使用的时候在一个一个依次调用
优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机
缺点:没有面向对象易维护、易复用、易扩展
面向对象OPP:
把事务分解成对象的形式,看看对象有什么功能,再把功能使用起来
优点:灵活、代码可复用、容易维护和开发,适合多人合作的大型项目
特性:封装性、继承性、多态性
类和对象:
类:ES6新增加的概念,可以使用class关键字声明一个类,之后以这个类来实例化对象
类抽象了对象的公共部分,它泛指某一大堆(class)
1.创建类:
class Star{
constructor(uname,age){
this.uname=uname;
this.age=age;
}
}
.利用类创建对象new,new会自动执行constructor构造函数
var ldh=new Star('刘德华');
console.log(ldh.uname) //刘德华
var zxy=new Star('张学友',20)
console.log(zxy)//uname:张学友,age:20
(1) 通过class 关键字创建类, 类名我们还是习惯性定义首字母大写
(2) 类里面有个constructor 函数,可以接受传递过来的参数,同时返回实例对象
(3) constructor 函数 只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个函数,类也会自动生成这个函数
(4) 生成实例 new 不能省略
(5) 最后注意语法规范, 创建类 类名后面不要加小括号,生成实例 类名后面加小括号, 构造函数不需要加function
2.类中添加方法
class Star{
constructor(uname,age){
this.uname=uname;
this.age=age;
}
sing(song){
console.log(this.uname+song);
}
}
var ldh=new Star('刘德华');
console.log(ldh.uname)
var zxy=new Star('张学友',20)
console.log(zxy)
ldh.sing('冰雨')//刘德华冰雨
zyx.sing('李香兰')//张学友李香兰
(1)类里面不需要写function
(2)多个函数方法之间不需要添加逗号分隔
3.类的继承
class Father {
constructor() {
}
money() {
console.log(100);
}
}
class Son extends Father { //使用extends继承
}
var son = new Son();
son.money();
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
class Son extends Father {
constructor(x, y) {
super(x, y); //调用了父类中的构造函数
}
}
var son = new Son(1, 2);
var son1 = new Son(11, 22);
son.sum();
son1.sum();
super关键字用于访问和调用父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
say() {
// console.log('我是儿子');
console.log(super.say() + '的儿子');
// super.say() 就是调用父类中的普通函数 say()
}
}
var son = new Son();
son.say();
// 继承中的属性或者方法查找原则: 就近原则
// 1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
// 2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
扩展运算符继承
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
// 子类继承父类加法方法 同时 扩展减法方法
class Son extends Father {
constructor(x, y) {
// 利用super 调用父类的构造函数
// super 必须在子类this之前调用
super(x, y);
this.x = x;
this.y = y;
}
subtract() {
console.log(this.x - this.y);
}
}
var son = new Son(5, 3);
son.subtract();
son.sum();
类的注意事项:
1. 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象
2. 类里面的共有的属性和方法一定要加this使用
构造函数和原型:
1、利用构造函数创建对象
// 1. 利用 new Object() 创建对象
var obj1 = new Object();
// 2. 利用 对象字面量创建对象
var obj2 = {};
// 3. 利用构造函数创建对象
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(ldh);
ldh.sing();
zxy.sing();
构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量初始值,它总与new一起使用,我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面
在JS中,使用构造函数时,要注意以下两点:
1.构造函数用于创建某一类对象,其首字母要大写
2.构造函数要和new一起使用才有意义
new在执行时会做四件事情:
1.在内存中创建一个新的空对象
2.让this指向这个新的对象
3.执行构造函数里面的代码,给这个新对象添加属性和方法
4.返回这个新对象(所以构造函数里面不需要return)
原型,原型链:
构造函数通过原型分配的函数是所有对象所共享的
JS规定,每一个构造函数都有一个prototype属性,指向另一个对象,prototype就是一个对象,这个对象的所有属性和方法都会被构造函数所拥有;
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法;
原型是一个对象,它可以共享方法,不会浪费内存
// 1. 构造函数的问题.
function Star(uname, age) {
this.uname = uname;
this.age = age;
// this.sing = function() {
// console.log('我会唱歌');
// }
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(ldh.sing === zxy.sing);
// console.dir(Star);
ldh.sing();
zxy.sing();
// 2. 一般情况下,我们的公共属性定义到构造函数里面, 公共的方法我们放到原型对象身上
对象原型proto:
对象都会有一个属性proto指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype 原型对象的属性和方法,就是因为有proto的存在
proto和prototype是等价的
原型constructor:
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
// 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
// Star.prototype.sing = function() {
// console.log('我会唱歌');
// };
// Star.prototype.movie = function() {
// console.log('我会演电影');
// }
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
constructor: Star,
sing: function() {
console.log('我会唱歌');
},
movie: function() {
console.log('我会演电影');
}
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(Star.prototype);
console.log(ldh.__proto__);
console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor);
原型链
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var ldh = new Star('刘德华', 18);
// 1. 只要是对象就有__proto__ 原型, 指向原型对象
console.log(Star.prototype);
console.log(Star.prototype.__proto__ === Object.prototype);
// 2.我们Star原型对象里面的__proto__原型指向的是 Object.prototype
console.log(Object.prototype.__proto__);
// 3. 我们Object.prototype原型对象里面的__proto__原型 指向为 null
原型、原型链的总结:
原型:每一个构造函数都有一个prototype属性指向一个对象,这个对象就是构造函数实例的原型
原型链:每一个实例都有一个proto属性指向原型对象,来获取原型对象上的属性和方法,原型对象也有一个proto属性指向另外一个原型对象,以此类推,直到原型链的最终端null为止,这个串成链的过程就是原型链
扩展内置对象方法:
// 原型对象的应用 扩展内置对象方法
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
};
// Array.prototype = {
// sum: function() {
// var sum = 0;
// for (var i = 0; i < this.length; i++) {
// sum += this[i];
// }
// return sum;
// }
// }
var arr = [1, 2, 3];
console.log(arr.sum());
console.log(Array.prototype);
var arr1 = new Array(11, 22, 33);
console.log(arr1.sum());
改变this指向: call
// call 方法
function fn(x, y) {
console.log('我想喝手磨咖啡');
console.log(this);
console.log(x + y);
}
var o = {
name: 'andy'
};
// fn();
// 1. call() 可以调用函数
// fn.call(); 也可以调用函数
// 2. call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象
fn.call(o, 1, 2);
利用父构造函数继承:
// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
var son = new Son('刘德华', 18, 100);
console.log(son);
用call在Son构造函数里面调用了Father构造函数,此时把调用过来的Father的this 修改成了Son的this,因为是在Son里面调用的
利用原型对象继承方法
// 借用父构造函数继承属性
// 1. 父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() {
console.log(100000);
};
// 2 .子构造函数
function Son(uname, age, score) {
// this 指向子构造函数的对象实例
Father.call(this, uname, age);
this.score = score;
}
// Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function() {
console.log('孩子要考试');
}
var son = new Son('刘德华', 18, 100);
console.log(son);
console.log(Father.prototype);
console.log(Son.prototype.constructor);
直接把父构造函数原型对象赋给子构造函数原型对象,会导致直接父构造函数也会有子构造函数的方法,所以先让父构造函数实例一下创建一个新的实例对象,实例对象的对象原型proto指向父构造函数,因此实例对象会有父构造函数的方法,再把实例对象赋给子构造函数的原型对象,子构造函数就会有父构造函数的方法,父构造函数也不会有子构造函数的方法
类的本质:
1.class本质还是function.
2.类的所有方法都定义在类的prototype属性上
3.类创建的实例,里面也有proto指向类的prototype原型对象
4.所以ES6的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
5.所以ES6的类其实就是语法糖.
6.语法糖:语法糖就是一种便捷写法.简单理解,有两种方法可以实现同样的功能,但是一种写法更加清晰、方便,那么这个方法就是语法糖
ES5新增的数组方法:forEach() map() filter() some() every():
forEach(): foreach和some的区别:foreach里面使用return 不能停止循环,some中遇到return就会终止(必须是true,因为some的特性就是找到返回true就会终止)
// forEach 迭代(遍历) 数组
var arr = [1, 2, 3];
var sum = 0;
arr.forEach(function(value, index, array) {
console.log('每个数组元素' + value);
console.log('每个数组元素的索引号' + index);
console.log('数组本身' + array);
sum += value;
})
console.log(sum);
filter(): 返回一个新数组
// filter 筛选数组
var arr = [12, 66, 4, 88, 3, 7];
var newArr = arr.filter(function(value, index) {
// return value >= 20;
return value % 2 === 0;
});
console.log(newArr);
some():查找数组中是否有满足条件的元素,返回的是布尔值,能查找到就返回true,查找不到返回false,能查找到满足第一个条件的元素终止循环,没查找到就继续循环
// some 查找数组中是否有满足条件的元素
// var arr = [10, 30, 4];
// var flag = arr.some(function(value) {
// // return value >= 20;
// return value < 3;
// });
// console.log(flag);
var arr1 = ['red', 'pink', 'blue'];
var flag1 = arr1.some(function(value) {
return value == 'pink';
});
console.log(flag1);
filter 也是查找满足条件的元素 返回的是一个数组 而且是把所有满足条件的元素返回回来
some 也是查找满足条件的元素是否存在 返回的是一个布尔值 如果查找到第一个满足条件的元素就终止循环
trim():去除两端的空格 返回字符串
// trim 方法去除字符串两侧空格
var str = ' an dy ';
console.log(str);
var str1 = str.trim();
console.log(str1);
var input = document.querySelector('input');
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.onclick = function() {
var str = input.value.trim();
if (str === '') {
alert('请输入内容');
} else {
console.log(str);
console.log(str.length);
div.innerHTML = str;
}
}
对象方法:
Object.keys() 获取对象自身的所有属性
// 用于获取对象自身所有的属性
var obj = {
id: 1,
pname: '小米',
price: 1999,
num: 2000
};
var arr = Object.keys(obj);
console.log(arr);
arr.forEach(function(value) {
console.log(value);
})
Object.defineProperty() 定义对象中新属性或修改原有的属性
Object.defineProperty(obj,prop,descriptor) obj:目标对象 prop:需定义或修改的属性的名字 descriptor目标属性所拥有的特性
Object.defineProperty)第三个参数descriptor说明︰以对象形式{}书写
value:设置属性的值 默认为undefined
writable:值是否可以重写 。true | false 默认为false
enumerable:目标属性是否可以被遍历。true | false默认为false
configurable:目标属性是否可以被删除或是否可以再次修改特性true | false 默认为false
// Object.defineProperty() 定义新属性或修改原有的属性
var obj = {
id: 1,
pname: '小米',
price: 1999
};
// 1. 以前的对象添加和修改属性的方式
// obj.num = 1000;
// obj.price = 99;
// console.log(obj);
// 2. Object.defineProperty() 定义新属性或修改原有的属性
Object.defineProperty(obj, 'num', {
value: 1000,
enumerable: true
});
console.log(obj);
Object.defineProperty(obj, 'price', {
value: 9.9
});
console.log(obj);
Object.defineProperty(obj, 'id', {
// 如果值为false 不允许修改这个属性值 默认值也是false
writable: false,
});
obj.id = 2;
console.log(obj);
Object.defineProperty(obj, 'address', {
value: '中国山东蓝翔技校xx单元',
// 如果只为false 不允许修改这个属性值 默认值也是false
writable: false,
// enumerable 如果值为false 则不允许遍历, 默认的值是 false
enumerable: false,
// configurable 如果为false 则不允许删除这个属性 不允许在修改第三个参数里面的特性 默认为false
configurable: false
});
console.log(obj);
console.log(Object.keys(obj));
delete obj.address;
console.log(obj);
delete obj.pname;
console.log(obj);
Object.defineProperty(obj, 'address', {
value: '中国山东蓝翔技校xx单元',
// 如果值为false 不允许修改这个属性值 默认值也是false
writable: true,
// enumerable 如果值为false 则不允许遍历, 默认的值是 false
enumerable: true,
// configurable 如果为false 则不允许删除这个属性 默认为false
configurable: true
});
console.log(obj.address);
函数进阶:
创建函数的方式:
// 函数的定义方式
// 1. 自定义函数(命名函数)
function fn() {};
// 2. 函数表达式 (匿名函数)
var fun = function() {};
// 3. 利用 new Function('参数1','参数2', '函数体');
var f = new Function('a', 'b', 'console.log(a + b)');
f(1, 2);
// 4. 所有函数都是 Function 的实例(对象)
console.dir(f);
// 5. 函数也属于对象
console.log(f instanceof Object); //前者等于后者吗?
调用函数方法:
// 函数的调用方式
// 1. 普通函数
function fn() {
console.log('人生的巅峰');
}
// fn(); fn.call()
// 2. 对象的方法
var o = {
sayHi: function() {
console.log('人生的巅峰');
}
}
o.sayHi();
// 3. 构造函数
function Star() {};
new Star();
// 4. 绑定事件函数
// btn.onclick = function() {}; // 点击了按钮就可以调用这个函数
// 5. 定时器函数
// setInterval(function() {}, 1000); 这个函数是定时器自动1秒钟调用一次
// 6. 立即执行函数
(function() {
console.log('人生的巅峰');
})();
// 立即执行函数是自动调用
函数的this指向:
// 函数的不同调用方式决定了this 的指向不同
// 1. 普通函数 this 指向window
function fn() {
console.log('普通函数的this' + this);
}
window.fn();
// 2. 对象的方法 this指向的是对象 o
var o = {
sayHi: function() {
console.log('对象方法的this:' + this);
}
}
o.sayHi();
// 3. 构造函数 this 指向 ldh 这个实例对象 原型对象里面的this 指向的也是 ldh这个实例对象
function Star() {};
Star.prototype.sing = function() {
}
var ldh = new Star();
// 4. 绑定事件函数 this 指向的是函数的调用者 btn这个按钮对象
var btn = document.querySelector('button');
btn.onclick = function() {
console.log('绑定时间函数的this:' + this);
};
// 5. 定时器函数 this 指向的也是window
window.setTimeout(function() {
console.log('定时器的this:' + this);
}, 1000);
// 6. 立即执行函数 this还是指向window
(function() {
console.log('立即执行函数的this' + this);
})();
Call方法及应用 特性:可以继承
// 改变函数内this指向 js提供了三种方法 call() apply() bind()
// 1. call()
var o = {
name: 'andy'
}
function fn(a, b) {
console.log(this);
console.log(a + b);
};
fn.call(o, 1, 2);
// call 第一个可以调用函数 第二个可以改变函数内的this 指向
// call 的主要作用可以实现继承
function Father(uname, age, sex) {
this.uname = uname;
this.age = age;
this.sex = sex;
}
function Son(uname, age, sex) {
Father.call(this, uname, age, sex);
}
var son = new Son('刘德华', 18, '男');
console.log(son);
apply方法及应用 特性:apply传参数必须是数组
// 改变函数内this指向 js提供了三种方法 call() apply() bind()
// 2. apply() 应用 运用的意思
var o = {
name: 'andy'
};
function fn(arr) {
console.log(this);
console.log(arr); // 'pink'
};
fn.apply(o, ['pink']);
// 1. 也是调用函数 第二个可以改变函数内部的this指向
// 2. 但是他的参数必须是数组(伪数组)
// 3. apply 的主要应用 比如说我们可以利用 apply 借助于数学内置对象求数组最大值
// Math.max();
var arr = [1, 66, 3, 99, 4];
var arr1 = ['red', 'pink'];
// var max = Math.max.apply(null, arr);
var max = Math.max.apply(Math, arr);
var min = Math.min.apply(Math, arr);
console.log(max, min);
bind方法及应用 特性:不能调用函数,返回的是改变指向后的函数
<button>点击</button>
<button>点击</button>
<button>点击</button>
<script>
// 改变函数内this指向 js提供了三种方法 call() apply() bind()
// 3. bind() 绑定 捆绑的意思
var o = {
name: 'andy'
};
function fn(a, b) {
console.log(this);
console.log(a + b);
};
var f = fn.bind(o, 1, 2);
f();
// 1. 不会调用原来的函数 可以改变原来函数内部的this 指向
// 2. 返回的是原函数改变this之后产生的新函数
// 3. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时用bind
// 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
// var btn1 = document.querySelector('button');
// btn1.onclick = function() {
// this.disabled = true; // 这个this 指向的是 btn 这个按钮
// // var that = this;
// setTimeout(function() {
// // that.disabled = false; // 定时器函数里面的this 指向的是window
// this.disabled = false; // 此时定时器函数里面的this 指向的是btn
// }.bind(this), 3000); // 这个this 指向的是btn 这个对象
// }
var btns = document.querySelectorAll('button');
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
this.disabled = true;
setTimeout(function() {
this.disabled = false;
}.bind(this), 2000);
}
}
闭包
// 闭包(closure)指有权访问另一个函数作用域中变量的函数。
// 闭包: 我们fun 这个函数作用域 访问了另外一个函数 fn 里面的局部变量 num
function fn() {
var num = 10;
function fun() {
console.log(num);
}
fun();
}
fn();
在作用域被访问的就是闭包
优点:可以访问函数作用于的局部变量
可以避免变量污染
缺点:不会被js垃圾回收机制回收,导致内存泄漏等问题
递归
// 递归函数 : 函数内部自己调用自己, 这个函数就是递归函数
var num = 1;
function fn() {
console.log('我要打印6句话');
if (num == 6) {
return; // 递归里面必须加退出条件
}
num++;
fn();
}
fn();
浅拷贝
拷贝地址,修改拷贝过来的属性,被拷贝的属性也会被修改
方法:for in、assign
// 浅拷贝只是拷贝一层, 更深层次对象级别的只拷贝引用.
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
}
};
var o = {};
// for (var k in obj) {
// // k 是属性名 obj[k] 属性值
// o[k] = obj[k];
// }
// console.log(o);
// o.msg.age = 20;
// console.log(obj);
console.log('--------------');
Object.assign(o, obj);//拷贝给谁 拷贝谁
console.log(o);
o.msg.age = 20;
console.log(obj);
深拷贝
方法:递归函数、...
拷贝过来的复杂数据类型开辟一个新的内存 修改后不会变
// 深拷贝拷贝多层, 每一级别的数据都会拷贝.
var obj = {
id: 1,
name: 'andy',
msg: {
age: 18
},
color: ['pink', 'red']
};
var o = {};
// 封装函数
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判断我们的属性值属于那种数据类型
// 1. 获取属性值 oldobj[k]
var item = oldobj[k];
// 2. 判断这个值是否是数组
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item)
} else if (item instanceof Object) {
// 3. 判断这个值是否是对象
newobj[k] = {};
deepCopy(newobj[k], item)
} else {
// 4. 属于简单数据类型
newobj[k] = item;
}
}
}
deepCopy(o, obj);
console.log(o);
var arr = [];
console.log(arr instanceof Object);
o.msg.age = 20;
console.log(obj);
ES6:
#### let 不存在变量提升
let 不影响作用域链
let 不能重复声明
let存在块级作用作用域 if else for while
let a;
let b,c,d;
let e=100;
let f=200,g='i love u',h=[];
//1、不能重复声明
let aa=1;
let aa=2;
//2 有块级作用域 if else for while
{
let bb=1;
}
console.log(bb)//报错 bb is not a defined
//3、不存在变量提升
console.log(lhb) //undefind var lhb;
var lhb=22;
let aaa=11;
//4、不影响作用域链
{
let pp=11;
function dudu(){
console.log(pp) //11
}
dudu();
}
const
1、存在块级作用域
2、一定要赋初始值
3、不能修改常量
4、一般常量用大写(潜规则)
5、对于数组和对象的元素修改,不算对常量进行修改,不会报错
解构赋值
1、数组的结构
let F4=['刘能','赵本山','小沈阳','宋小宝']
let [liu,zhao,xiao,song]=F4//给每个变量进行赋值
console.log(liu)//刘能
console.log(zhao)//赵本山
console.log(xiao)//小沈阳
console.log(song)//宋小宝
2、对象结构
const Zhao={
name:'赵本山',
age:'50',
xiaopin:function(){
console.log('我会演小品')
}
}
let {z,a,xp}=Zhao;
console.log(name)//赵本山
console.log(age)//50
console.log(xiaopin)//我会演小品
xiaopin();
模板字符串
//1、声明
let a=`我是一个字符串哦哈哈哈`
console.log(a,typeof a)//我是一个字符串哦哈哈哈 string
//2、可以直接换行
let st=`<ul>
<li>123</li>
<li>321</li>
<li>12345</li>
</ul>`
//3、变量拼接
let as='李一诺'
let out=`${as}是狗!` //固定写法 ${}
console.log(out);//李一诺是狗!
箭头函数
this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值
不能作为构造实例化对象
不能使用 arguments 变量
// ES6 允许使用「箭头」(=>)定义函数。
//声明一个函数
// let fn = function(){
// }
// let fn = (a,b) => {
// return a + b;
// }
//调用函数
// let result = fn(1, 2);
// console.log(result);
//1. this 是静态的. this 始终指向函数声明时所在作用域下的 this 的值
function getName(){
console.log(this.name);
}
let getName2 = () => {
console.log(this.name);
}
//设置 window 对象的 name 属性
window.name = '尚硅谷';
const school = {
name: "ATGUIGU"
}
//直接调用
// getName();
// getName2();
//call 方法调用
// getName.call(school);
// getName2.call(school);
//2. 不能作为构造实例化对象
// let Person = (name, age) => {
// this.name = name;
// this.age = age;
// }
// let me = new Person('xiao',30);
// console.log(me);
//3. 不能使用 arguments 变量
// let fn = () => {
// console.log(arguments);
// }
// fn(1,2,3);
//4. 箭头函数的简写
//1) 省略小括号, 当形参有且只有一个的时候
// let add = n => {
// return n + n;
// }
// console.log(add(9));
//2) 省略花括号, 当代码体只有一条语句的时候, 此时 return 必须省略
// 而且语句的执行结果就是函数的返回值
let pow = n => n * n;
console.log(pow(8));
参数默认值
//ES6 允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数, 一般位置要靠后(潜规则)
// function add(a,c=10,b) {
// return a + b + c;
// }
// let result = add(1,2);
// console.log(result);
//2. 与解构赋值结合
function connect({host="127.0.0.1", username,password, port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: 'atguigu.com',
username: 'root',
password: 'root',
port: 3306
})
rest参数
// ES6 引入 rest 参数,用于获取函数的实参,用来代替 arguments
// ES5 获取实参的方式
function date(){
console.log(arguments);
}
date('白芷','阿娇','思慧');
// rest 参数
function date(...args){
console.log(args);// filter some every map
}
date('阿娇','柏芝','思慧');
// rest 参数必须要放到参数最后
function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
// fn(1,2,3,4,5,6);
扩展运算符
有引用数据类型就是浅拷贝
//1. 数组的合并 情圣 误杀 唐探
const kuaizi = ['王太利','肖央'];
const fenghuang = ['曾毅','玲花'];
const zuixuanxiaopingguo = kuaizi.concat(fenghuang);
const zuixuanxiaopingguo = [...kuaizi, ...fenghuang];
console.log(zuixuanxiaopingguo);
//2. 数组的克隆
const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua];// ['E','G','M']
console.log(sanyecao);
//3. 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
const divArr = [...divs];
console.log(divArr);// arguments
对象添加symbol属性
添加的属性是具有唯一性的
//向对象中添加方法 up down
let game = {
name:'俄罗斯方块',
up: function(){},
down: function(){}
};
//声明一个对象
// let methods = {
// up: Symbol(),
// down: Symbol()
// };
// game[methods.up] = function(){
// console.log("我可以改变形状");
// }
// game[methods.down] = function(){
// console.log("我可以快速下降!!");
// }
// console.log(game);
//
let youxi = {
name:"狼人杀",
[Symbol('say')]: function(){
console.log("我可以发言")
},
[Symbol('zibao')]: function(){
console.log('我可以自爆');
}
}
console.log(youxi)
迭代器
自定义遍历属性,首先想到迭代器
for in返回属性名,for of 返回属性值
//声明一个数组
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//使用 for...of 遍历数组
// for(let v of xiyou){
// console.log(v);
// }
let iterator = xiyou[Symbol.iterator]();
//调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
Promise
//实例化 Promise 对象
const p = new Promise(function(resolve, reject){
setTimeout(function(){
//
// let data = '数据库中的用户数据';
// resolve
// resolve(data);
let err = '数据读取失败';
reject(err);
}, 1000);
});
//调用 promise 对象的 then 方法
p.then(function(value){
console.log(value);
}, function(reason){
console.error(reason);
})
Promise.then
//创建 promise 对象
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('用户数据');
// reject('出错啦');
}, 1000)
});
//调用 then 方法 then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定
//1. 如果回调函数中返回的结果是 非 promise 类型的属性, 状态为成功, 返回值为对象的成功的值
// const result = p.then(value => {
// console.log(value);
// //1. 非 promise 类型的属性
// // return 'iloveyou';
// //2. 是 promise 对象
// // return new Promise((resolve, reject)=>{
// // // resolve('ok');
// // reject('error');
// // });
// //3. 抛出错误
// // throw new Error('出错啦!');
// throw '出错啦!';
// }, reason=>{
// console.warn(reason);
// });
//链式调用
p.then(value=>{
}).then(value=>{
});
Promise.catch
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
//设置 p 对象的状态为失败, 并设置失败的值
reject("出错啦!");
}, 1000)
});
// p.then(function(value){}, function(reason){
// console.error(reason);
// });
p.catch(function(reason){
console.warn(reason);
});
Set(集合)
set可以存任何数据
//声明一个 set
let s = new Set();
let s2 = new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿']);
//元素个数
// console.log(s2.size);
//添加新的元素
// s2.add('喜事儿');
//删除元素
// s2.delete('坏事儿');
//检测
// console.log(s2.has('糟心事'));
//清空
// s2.clear();
// console.log(s2);
for(let v of s2){
console.log(v);
}
Set集合实践
let arr = [1,2,3,4,5,4,3,2,1];
//1. 数组去重
// let result = [...new Set(arr)];
// console.log(result);
//2. 交集
let arr2 = [4,5,6,5,6];
// let result = [...new Set(arr)].filter(item => {
// let s2 = new Set(arr2);// 4 5 6
// if(s2.has(item)){
// return true;
// }else{
// return false;
// }
// });
// let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
// console.log(result);
//3. 并集
// let union = [...new Set([...arr, ...arr2])];
// console.log(union);
//4. 差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
console.log(diff);
Map
map存的是键值对
//声明 Map
let m = new Map();
//添加元素
m.set('name','尚硅谷');
m.set('change', function(){
console.log("我们可以改变你!!");
});
let key = {
school : 'ATGUIGU'
};
m.set(key, ['北京','上海','深圳']);
//size
// console.log(m.size);
//删除
// m.delete('name');
//获取
// console.log(m.get('change'));
// console.log(m.get(key));
//清空
// m.clear();
//遍历
for(let v of m){
console.log(v);
}
// console.log(m);