es6学习(包括let和var、const)
参考链接:点击跳转
-
块级作用域 {}
ES5 中作用域有:全局作用域、函数作用域。没有块作用域的概念。ES6 中新增了块级作用域。块作用域由 { } 包括,if语句和 for语句里面的{ }也属于块作用域。
1.var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
2.let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
3.const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
**为什么要学习ES6
使用let关键字声明变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用let关键字声明变量</title>
</head>
<body>
<script type='text/javascript'>
// 1.let关键字就是用来声明变量的
// 2.使用let关键字声明的变量具有块级作用域 块级作用就是在一段函数里面起作用,在{}里起作用
//
// 3.在一个大括号{}中 使用let关键字声明的变量才具有块级作用域 var关键字是不具备这个特点的
//
// 4.防止循环变量变成全局变量
//
// 5.使用let关键字声明的变量没有变量提升
//
// 6.使用let关键字声明的变量具有暂时性死区特性
// 1.let关键字就是用来声明变量的
// let a = 10;
// console.log(a); //10
// //2.使用let关键字声明的变量具有块级作用域
// if (true) {
// let b = 20;
// console.log(20); //20
// if (true) {
// let c = 30;
// }
// console.log(c); //undefined
// }
// console.log(b); //undefined
// //3.在一个大括号{}中 使用let关键字声明的变量才具有块级作用域 var关键字是不具备这个特点的
// if (true) {
// let num = 100;
// var abc = 200;
// }
// console.log(num); //undefined
// console.log(abc); //200
// // 4.防止循环变量变成全局变量
// for (let i = 0; i < 2; i++) {} if(let i)和大括号绑定,所以可以一起用
// console.log(i); //undefined
// 5.使用let关键字声明的变量没有变量提升
// console.log(a); //不接受在没有设定初始值
// let a = 100;
// 6.使用let关键字声明的变量具有暂时性死区特性
var num = 10;
if (true) {
// 在这里 let 申明的变量和if 语句进行了绑定,
//所以不会受到外面的声明的影响,所以会报错误 不接受在没有设定初始值
console.log(num);
let num = 20;
}
</script>
</body>
</html>
es6学习基础
1.
- 面向对象编程 OOP
- 面向过程编程 POP
利用构造函数创建对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>利用构造函数创建对象</title>
</head>
<body>
<script type='text/javascript'>
// 1.利用 new Object()创建对象
var obje1 = new Object();
// 跟我们前面学的nwe Array()原理一致
// var obj = new Object();//创建了一个空的对象
// obj.uname = "张三丰";
// obj.age = 18;;
// obj.sex = "男 ";
// obj.sayHi = function () {
// console.log("hi~")
// }
// 2.利用 对象字面量创建对象
var obj2 = {}
// 对象字面量 : 就是花括号{}里面包含了表达这个具体事物(对象)的属性和方法
// 利用对象字面量创建对象{}
// var obj = {};//创建了一个空的对象
// var obj = {undefined
// uname : "张三丰",
// age : 18,
// sex : "男",
// sayHi : function() {undefined
// console.log("hi~")
// }
// }
// // (1)里面的属性或者方法我们采取建值对的形式 建 属性名 : 值 属性值
// // (2)多个属性或者方法中间最逗号隔开的
// // (3) 方法冒号后面跟的是一个匿名函数
// 3.利用构造函数创建对象
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('张学友', 19)
var zxy = new Star('刘德华', 10)
console.log(ldh);
ldh.sing()
</script>
</body>
</html>
对象里面的静态成员和实例成员
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>静态成员和实例成员</title>
</head>
<body>
<script type='text/javascript'>
function Star(uname, age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华', 19)
// 实例成员 都是this.。。。添加的 是函数它本身就有的
// 1.实例成员就是构造函数内部通过this添加的成员 uname age sing 就是实例成员
// 实例成员只能通过实例化对象来访问 也就是 new 的ldh
console.log(ldh.age);
console.log(ldh.uname);
ldh.sing()
// console.log(Star.name);//undefined 不可以通过构造函数来访问实例成员
// 2. 静态成员 在构造函数本身上添加的成员 sex 就是静态成员
Star.sex = '男'
// 静态成员只能通过构造函数来访问
console.log(Star.sex);
// console.log(ldh.sex);// undefinend 不能通过对象来访问
</script>
</body>
</html>
终于等到原型啦
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型</title>
</head>
<body>
<script type='text/javascript'>
// 1.构造函数的问题 .直接定义在上面就每一次实例化的时候都要为里面的方法新开辟一个空间内存,浪费内存
function Star(uname, age) {
this.uname = uname;
this.age = age;
// this.sing = function() {
// console.log('我会唱歌');
// }
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
// console.log(ldh.sing === zxy.sing);// true
var ldh = new Star('刘德华', 19)
var zxy = new Star('张学友', 29)
ldh.sing()
//2.一般情况下 我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象身上
</script>
</body>
</html>
_proto_对象原型 其实它和prototype原型对象等价
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>对象原型_proto_</title>
</head>
<body>
<script type='text/javascript'>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var ldh = new Star('刘德华', 19)
var zxy = new Star('张学友', 29)
ldh.sing()
console.log(ldh); //对象身上系统自己添加一个_proto_指向我们构造函数的原型对象prototype
console.log(ldh._proto_ === Star.prototype); //true
//方法的查找原则: 首先先看ldh对象身上是否有 sing 方法,如果有就执行这个对象上的sing
// 如果没有sing 这个方法, 因为有_proto_的存在,就去构造函数原型对象prototype身上查找sing这个方法
</script>
</body>
</html>
constructor代表原型函数,通常用来指回原来的原型函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型constructor</title>
</head>
<body>
<script type='text/javascript'>
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(ldh);
console.log(Star.prototype);
console.log(zxy.__proto__);
// console.log(ldh.__proto__ === Star.prototype); //true
console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor);
</script>
</body>
</html>
prototype(原型对象) 和 proto_(对象原型) constructor(构造函数)三者之间的关系
-实例化对象的对象原型ldh.__proto__等价于构造函数的原型对象Star.prototype 然后里面的滴 constructor(原型函数-构造函数)代表的就是它原来的原型函数呀。
原型链
- 它是通过ldh.__proto__找,没有就往上找,Star.prototype 没有再通过Star.prototype.__proto__往上找到 Object.prototype 它身上没有想要的方法属性的话,它再通过Object.prototype.__proto__找就为null了。
```<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型链</title>
</head>
<body>
<script type='text/javascript'>
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); //原型对象也是一个对象,所以它也有__proto__
console.log(Star.prototype.__proto__ === Object.prototype) //true
console.log(Object()) //居然是个{}
//2.我们Stra原型对象里面的__proto__原型指向的是 Object.prototype
console.log(Object.prototype.__proto__); //null
// 3. 我们Object.prototype原型对象里面的__proto__原型 指向为 null
</script>
</body>
</html>
原型链成员查找规则
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型链成员查找规则</title>
</head>
<body>
<script type='text/javascript'>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
// Star.prototype.sex = '女'
var ldh = new Star('刘德华', 19)
// console.log(ldh.sex); //女
Object.prototype.sex = '男'
var Obj = new Object()
//特别提醒 实列成员只能通过实例对象来访问
Obj.__proto__.la = '聪明'
console.log(ldh.la); //聪明
console.log(ldh.sex); //男
// 还有 只有 Object的原型对象上有 toString()
// Object 它下面的都没有
console.log(ldh.toString());
</script>
</body>
</html>
原型对象中的this指向
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原型对象中的this指向</title>
</head>
<body>
<script type='text/javascript'>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
var that
Star.prototype.sing = function() {
console.log('我会唱歌');
that = this
}
var ldh = new Star('刘德华', 18);
// console.log(that);//没有调用的时候它为undefined
ldh.sing()
console.log(that);
// 2.原型对象函数里面的this 指向的是 实例对象 ldh
</script>
</body>
</html>
扩展内置对象方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>扩展内置对象方法</title>
</head>
<body>
<script type='text/javascript'>
// 原型对象的应用 扩展内置对象方法
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i]
}
return sum
}
//不要这样赋值会把原来的给覆盖掉
// Array.prototype = {
// function() {
// var sum = 0;
// for (var i = 0; i < this.length; i++) {
// sum += this[i]
// }
// return sum
// }
// }
// 只要是数组它就自然能识别???
var Arr = [1, 2, 3] //var Arr = new Array() Arr=[1,2,3]
//记住调用的时候记得加括号它是个函数 不是一个属性 属性才不加括号
console.log(Arr.sum()); //6
console.log(Arr.sum);
</script>
</body>
</html>
call方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>call方法</title>
</head>
<body>
<script type='text/javascript'>
// call 方法
function fn(x, y) {
console.log('我想喝手磨咖啡');
console.log(x + y);
console.log(this);
}
var o = {
name: 'andy'
}
// fn()
// fn.call()
// 1. call() 可以调用函数 call(想要指向的对象, 参数1,参数2)
// fn.call()
//2.call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o 这个对象
fn.call(o, 2, 3)
</script>
</body>
</html>
借用父构造函数继承属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>借用父构造函数继承属性</title>
</head>
<body>
<script type='text/javascript'>
// 借用父构造函数继承属性
// 1.父构造函数
function Father(uname, age) {
// this 指向父构造函数的对象实例 也就是 var father = new Father() 那么this 就指向 father
this.uname = uname;
this.age = age
}
// 2.子构造函数
//这里也要传入。
function Son(uname, age, score) {
//this 指向子构造函数的对象实例
Father.call(this, uname, age)
// 它把父构造函数的this 指向了该调用它的实例对象的this 再传入父构造函数想要继承的属性
// 不传入就是undefined
this.score = score
}
var son = new Son('刘德华', 18, 100)
console.log(son);
</script>
</body>
</html>
借用原型对象继承方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>借用原型对象继承方法</title>
</head>
<body>
<script type='text/javascript'>
// 借用父构造函数继承属性
// 1.父构造函数
function Father(uname, age) {
//this 指向父构造函数的对象实例 也就是 var father = new Father() 那么this 就指向 father
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
}
var son = new Son('刘德华', 18, 100)
console.log(son);
// 相当于把Son.prototype指向了Father.prototype 就是一个指针把地址给指过去了,改变的当然是 Father.prototype上面肯定有less方法
// 怎么解决呢?
// Son.prototype = Father.prototype 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
console.log(Son.prototype);
// 这个是子构造函数专门的方法
Son.prototype.less = function() {
console.log('less 方法');
}
//这时 Father.prototype 也有less方法。
console.log(Father.prototype);
// 解决
// 新开辟一个实例对象,这个地址和原来的Father地址不一样,是新开辟的,但是它通过__ptoto__可以继承了Father.prototype
//如果利用对象的形式修改了原型对象,别忘了利用constructor指回来构造函数
Son.prototype = new Father() //它的constructor变成了Father了
// 这里是赋值操作,所以原来的 Son.prototype的this指向的就是Father了
//(原来的Son构造函数里面的this指向原来是指 它的实例对象的,但是
// 这个赋值操作让它的地址那些的this指向了 Father;
// 要想让它指回来就要用到constructor--原型构造函数
console.log(Son.prototype);
Son.prototype.constructor = son //把它的原型构造函数给指回来。
//请记住
// constructor就是原构造函数 也就是son.__proto__.constructor 为2.子构造函数//son.__proto__== Son.prototype
//同理 Father.prototype.constructor 为Father()
// 所以原型构造函数的this肯定也会发生改变。因为它把整个原型对象都给赋值了,
</script>
</body>
</html>
函数的定义和调用方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>函数的定义和调用方式</title>
</head>
<body>
<script type='text/javascript'>
// 函数的定义方式
//1.自定义函数(命名函数)
// function fn () {}
//2. 函数表达式(匿名函数)
// var fn = function () {}
//3.利用 new Function('参数1', '参数2', '函数体');
// var f = new Function('a', 'b', 'console.log(a + b)');
// console.log('''');//语法错误
// 昂包记住 要么外面是双引号里面是单引号,要么外面是单引号里面是双引号
var fn1 = new Function('console.log("兔")');
fn1()
var fn = new Function('a', 'b', 'console.log(a+b)')
fn(1, 2)
// console.dir(fn); 里面有constructor 证明它有原型对象,它是对象
// instanceof 判断前面是不是属于后面
console.log(fn instanceof Object); // true 证明这样定义的函数是对象,但是这个不常用,不懂。
</script>
</body>
</html>
函数的调用方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>函数的调用方式</title>
</head>
<body>
<script type='text/javascript'>
//函数的调用方式
//1. 普通函数
function fn() {
console.log('人生巅峰');
}
// fn(); fn.call call() 可以调用函数
//call(想要指向的对象, 参数1,参数2) 可以改变这个函数的this指向
//2.对象的方法
var o = {
sayHiy: function() {
console.log('人生的巅峰');
}
}
o.sayHiy();
//3.构造函数
function Star() {}
new Star();
// 4.绑定事件函数
// btn.onclick = function() {} // 点击了按钮就可以调用这个函数
// 5. 定时器函数
// setInterval(function () {},1000); 这个函数是定时器自动1秒钟调用一次
// 6.立即执行函数
(function() {
console.log('人生的巅峰');
})()
//立即执行函数是自动调用
</script>
</body>
</html>
普通函数的this的指向问题
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>this的指向问题</title>
</head>
<body>
<button>点击</button>
<script type='text/javascript'>
//函数的不同调用方式决定了this的指向不同
//1. 普通函数this指向window
function fn() {
console.log('普通函数的this' + this);
}
window.fn();
//2.对象的方法 this 指向的是对象o
var o = {
sayHiy: function() {
console.log('对象方法的this' + this);
}
}
o.sayHiy();
//3.构造函数this指向ldh这个实例对象 原型对象里面的this指向的也是ldh这个实例对象
function Star() {}
var ldh = new Star();
Star.prototype.sing = function() {
//指向调用者 也就是ldh
}
// 4.绑定事件函数 this 指向的是函数的调用者btn这个按钮对象
var btn = document.querySelector('button');
btn.onclick = function() {
console.log('绑定时间函数的this:' + this);
}
// 5. 定时器函数
setInterval(function() {
console.log('定时器的this' + this);
}, 1000); //这个函数是定时器自动1秒钟调用一次
// 6.立即执行函数
(function() {
console.log('立即执行函数的this' + this);
})()
//立即执行函数是自动调用
</script>
</body>
</html>
一点面试题
- 它先去找全局作用域下面的i的值 而且从上往下执行所以先执行循环体的i
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type='text/javascript'>
var arr = []
for (var i = 0; i < 2; i++) {
arr[i] = function() {
console.log(i);
}
}
arr[1]() //2 牛啊,循环早就结束了,
//它才去里面调用,这时i就等于2 ,函数的函数体是输出i 循环结束i为2,所以打印出来是2
</script>
</body>
</html>
let
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>let</title>
</head>
<body>
<script type='text/javascript'>
let a;
let b, c, d;
let e = 100,
g = 'girl',
h = []
//变量不能重复声明
let pig = '小住';
let pig = '大家'
// console.log(pig);报错
// 2.块级作用域 全局,函数,eval--也就是代码块
// if else while for
{
let girl = '周扬青';
}
// console.log(girl); 报错
// 3.不存在变量提升
console.log(song); //报错
let song = '恋爱达人'
// 4.不影响作用域链
{
let school = '尚硅谷';
function fn() {
console.log(school); //没有它就往上找。
}
}
fn();
</script>
</body>
</html>
let的重点案例一定要看
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>let实践案例</title>
<style>
.item {
float: left;
width: 100px;
height: 100px;
border: 2px solid green;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="container">
<h2 class="page-header">切换颜色</h2>
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<script type='text/javascript'>
let items = document.getElementsByClassName('item');
// for (var i = 0; i < items.length; i++) {
// items[i].onclick = function() {
// //修改当前元素的背景颜色
// // this.style.background = 'pink';
// items[i].style.background = 'pink'
// }
// }
// //循环结束之后 i的值变为3。当你点击的时候它就去找items[3]结果发现没有所以报错
// {
// var i = 0;
// }
// {
// var i = 1;
// }
// {
// var i = 2;
// }
for (let i = 0; i < items.length; i++) {
items[i].onclick = function() {
//修改当前元素的背景颜色
// this.style.background = 'pink';
items[i].style.background = 'pink'
console.log(i);
}
}
//循环结束之后 i的值变为3。当你点击的时候它就去找items[3]结果发现没有所以报错
//这里的代码块是互不影响的
// {
// let i = 0;
// 这时点击它发现 i 没有 就往上找 找到了开辟的 i 为0,然后 i=0,items[0]就变颜色
// items[i].onclick = function() {
// //修改当前元素的背景颜色
// // this.style.background = 'pink';
// items[i].style.background = 'pink'
// }
// }
// {
// let i = 1;
// }
// {
// let i = 2;
// }
</script>
</body>
</html>
const
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>const 定义常量</title>
</head>
<body>
<script type='text/javascript'>
//记住:定义常量就是 常量就是不能变的值。
// 声明常量
const SCHOOL = '尚硅谷';
//1、一定要赋初始值
const A;
//2、一般常量使用大写(潜规则)
// const a = 100;小写也不会报错
//3. 常量的值不能修改
//SCHOOL = 'NIHAO'
// 4.块级作用域
// {
// const PLAYER = 'UZI'
// }
// console.log(PLAYER);//报错
// 5.对于数组和对象的元素修改,不算做对常量的修改,不会报错(因为,数组地址未发生改变,改变的只是里面的值)
// const TEAM = ['UZT','JZJ','SAA']
// TEAM.push('MSA') 会添加进去
</script>
</body>
</html>
面向对象和面向过程
ES6中的类和对象
创建类和对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>创建类和对象</title>
</head>
<body>
<!-- 类可以理解为一个模板,而对象就是根据这个模板造出来的具体实例。.还有万物皆对象 -->
<!-- 创建一个类 class name {} -->
<script type="text/javascript">
//1. 创建类 class 创建一个明星类
class Strat {
constructor(name, age) {
this.name = name,
this.age = age
}
}
class Name {
}
var name = new Name('name', 20)
console.log(name); //[object Object]
// 2.利用类创建对象 new
var ldh = new Strat('刘德华', 19);
var zxy = new Strat('张学友', 20)
console.log(ldh);
console.log(zxy);
console.log(Strat);
//(1) 通过class 关键字创建类,类名我们还是习惯性定义首字母大写
// (2)类里面有个constructor 函数,可以接受传递过来的参数,同时返回实例对象(不需要我们写return它会自动返回)
// (3)constructor 函数,只要new生成实例时,就会自动调用这个函数,如果我们不写这个函数
// 类也会自动生成这个函数
// (4)生成实例new 不能省略
//(5)最后注意语法规范,创建类 类名后面不要加小括号,生成实例 类名后面加小括号,构造函数不需要
// 加function
</script>
</body>
</html>
类中添加方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>类中添加方法</title>
</head>
<body>
<script type="text/javascript">
// 1.创建类 class 创建一个 明星类
class Strat {
// 类的共有属性放到 constructor 里面
constructor(name, age) {
this.name = name;
this.age = age
}
//this指的是实例对象.
sing(song) {
console.log(this.name + song);
}
}
// 2.利用类创建对象 new
var ldh = new Strat('刘德华', 20)
var zxy = new Strat('张学友', 18)
console.log(ldh);
console.log(zxy);
// (1) 我们类里面所有的函数不需要写 function
//(2)多个函数方法之间不需要添加逗号分割。
ldh.sing('春语')
zxy.sing('冰冷的心')
</script>
</body>
</html>
类的继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>类的继承</title>
</head>
<body>
<script type="text/javascript">
// 1. 类的继承
// class Father {
// constructor() {}
// monery() {
// console.log(1000);
// }
// }
// class Son extends Father {
// }
// console.log(Son.monery); //undefined,要创建实例才可以用因为它是类是属性的集合。
// console.log(Son);
// //new 实例化对象才可以使用它里面的方法
// var son = new Son()
// son.monery()
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)
son.sum()
var son1 = new Son(1, 33)
son1.sum()
// class Father {
// constructor(x, y) {
// this.x = x;
// this.y = y
// }
// sum(x,y) {
// console.log(x + y);
// }
// }
// class Son extends Father {
// constructor(x, y) {
// super(x, y)//调用了父类中的构造函数
// }
// }
// var son = new Son(1, 2)
// son.sum(1,2)//3
// var son1 = new Son(1, 33)
// son1.sum(1,22)//23
</script>
</body>
</html>
super关键字调用父类普通函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>super关键字调用父类普通函数</title>
</head>
<body>
<script type="text/javascript">
//super 关键字调用父类普通函数
class Father {
say() {
return '我是爸爸'
// console.log('我是爸爸');这里要返回接收。这里被调用就是undefined
}
}
class Son extends Father {
say() {
console.log(super.say() + '的儿子');
// super.say() 就是调用父类中的普通函数 say()
}
}
var son = new Son()
son.say()
// 继承中的属性或者方法查找原则: 就近原则
// 1. 继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的
// 2. 继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
</script>
</body>
</html>
子类继承父类方法的同时扩展自己方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>子类继承父类方法的同时扩展自己方法</title>
</head>
<body>
<script type="text/javascript">
// 父类有加法方法
class Father {
// 类里面有个constructor 函数,可以接受传递过来的参数,同时返回实例对象(不需要我们写return它会自动返回)
//如果是有参数传递的话应该必须使用constructor?
// constructor(x, y) {
// this.x = x;
// this.y = y;
// }
sum(x, y) {
//假如这里不是this.x那么肯定不会有联系
// console.log(this.x + this.y);
console.log(x + y);
}
}
// 子类继承父类方法的同时 扩展减法方法
class Son extends Father {
constructor(x, y) {
// super 必须在子类this之前调用 为啥?
// 利用super 调用父类的构造函数,这样里面的this就是父类的this了,
super(x, y) //继承父类的x,y。所以可以使用里面的sum方法 调用了父类中的构造函数,里面返回的是实例对象,所以这里
// 也可以调用里面的方法?你看传入的参数就知道了。其实里面的方法是一直继承下来的。但是要用super调用。
//super关键字用于访问和调用对象父类上的函数。可以调用父亲的构造函数,也可以调用父类的普通函数
//毫无关系的方法调用时 super.方法()
//必须使用 super(x,y)接收传递过来的参数
this.x = x;
this.y = y
}
substract() {
console.log(this.x - this.y);
}
}
var son = new Son(9, 2)
son.sum(9, 1)
son.substract()
console.log(son);
</script>
</body>
</html>
使用类注意事项
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用类注意事项</title>
</head>
<body>
<button>点击</button>
<script type="text/javascript">
// var ldh = new Star('刘德华', 19)
// ldh.sing()
var that
var _that
var _that_
class Star {
constructor(name, age) {
// constructor 里面的this 指向的是 创建的实例对象
//指向的是实例对象
that = this
this.name = name;
this.age = age
// this.sing();
this.btn = document.querySelector('button')
this.btn.onclick = this.sing //写为this.sing()为什么不加小括号呢?加了一上来就调用了为什么呢?不是函数的调用都要加小括号吗?
//函数只要是要调用它进行执行的,都必须加括号。此时,函数实际上等于函数的返回值或者执行效果,
// 当然,有些没有返回值,但已经执行了函数体内的行为,就是说,加括号的,就代表将会执行函数体代码。
// 不加括号的,
// 都是把函数名称作为函数的指针,一个函数的名称就是这个函数的指针,此时不是得到函数的结果,
// 因为不会运行函数体代码。它只是传递了函数体所在的地址位置,在需要的时候好找到函数体去执行。
//等到我们点击按钮进行完成之后,它就会顺着这个指针去找到函数的位置,然后执行。
// 你就记住,只要有回调函数(就是后面才调用),都是异步的。因为必须有个前提条件触发它,所以叫异步。否则按正常顺序来就是同步了
}
sing() {
// 这个sing方法里面的this 指向的是 btn 这个按钮,因为这个按钮调用了这个函数
console.log(that.name); // that里面存储的是constructor里面的this
_that = this
console.log(this);
}
dance() {
// 这个dance里面的this 指向的是实例对象 ldh 因为ldh 调用了这个函数
_that_ = this;
console.log(this);
}
}
var ldh = new Star('刘德华', 19)
ldh.dance();
// console.log(ldh);
console.log(that === ldh);
// ldh.sing()
console.log(_that === ldh); //false
console.log(_that); //点击的时候 _that指向的是button
// ldh.sing()
// 1. 在 ES6 中类没有变量提升,所以必须先定义类,才能通过类实例化对象
// 2. 类里面的共有的属性和方法一定要加this使用.
</script>
</body>
</html>
改变函数内this 指向apply方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>改变函数内this 指向apply方法</title>
</head>
<body>
<script type="text/javascript">
//改变函数内this指向 js提供了三种方法 call() apply() bind()
// 2.apply()应用 运用的意思
var o = {
name: 'andy'
}
function fn(last) {
console.log(this);
console.log(last);
}
var ap = fn.apply(o) //因为没有传入参数 所以last打印出来是undefined
// console.log(ap);
var arr = [1, 2, 3, 0, 99]
fn.apply(o, ['pink'])
// 1.也是调用函数 第二个可以改变函数内部的this指向
//2. 但是他的参数必须是数组(伪数组)
// 3. apply的主要应用比如说我们可以利用apply借助于数学内置对象求数组的最大值
//Math.max()
var max = Math.max.apply(Math, arr)
console.log(max);
var min = Math.min.apply(Math, arr)
console.log(min);
</script>
</body>
</html>
改变函数内this指向bind方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>改变函数内this指向bind方法</title>
</head>
<body>
<button>点击</button>
<button>点击</button>
<button>点击</button>
<script type="text/javascript">
// 改变函数this指向 js 提供了三种方法 call() apply() bind()
// bind () 绑定的意思
var o = {
name: "andy"
}
function fn(a, b) {
console.log(this);
console.log(a + b);
}
var f = fn.bind(o, 1, 2) //call apply是一写就调用了 而他不会自动调用。
f();
//1.不会调用原来的函数, 可以改变原来函数内部发this指向
// 2. 返回的是原函数改变this之后产生的新函数
//3. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部发this指向此时用binf
// 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
// var btn = document.querySelector('button')
// btn.onclick = function() {
// this.disabled = true;
// setInterval(() => {
// btn.disabled = false
// }, 3000)
// }
// setInterval定时器 循环执行。
// setTimeout 点击的时候执行
// btn.onclick = function() {
// this.disabled = true
// setTimeout(function() {
// // btn.disabled = false // 定时器函数里面的this 指向的是window
// this.disabled = false;// 此时定时器函数里面的this 指向的是btn
// }.bind(this), 3000)// 这个this 指向的是btn 这个对象
// //为啥写在函数外面呢而不写到setTimeout外面呢。--你想改变哪个函数的内部this指向你就写哪个函数外面
//
// }
// disabled 残废的
var btns = document.querySelectorAll('button')
// for (let i = 0; i < btns.length; i++) {
// btns[i].onclick = function() {
// console.log(i);
// this.disabled = true;
// setTimeout(function() {
// this.disabled = false
// }.bind(this), 2000)
// }
// }
//用let 没有问题
// for (let i = 0; i < btns.length; i++) {
// btns[i].onclick = function() {
// console.log(i);
// this.disabled = true;
// setTimeout(function() {
// btns[i].disabled = false
// }, 2000)
// }
// }
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
console.log(i);
this.disabled = true;
setTimeout(function() {
this.disabled = false
}.bind(this), 2000)
}
}
</script>
</body>
</html>
call 和apply bind 应用场景
开启严格模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>开启严格模式</title>
</head>
<body>
<!-- 为整个脚本(script标签)开启严格模式 -->
<script type="text/javascript">
'use strict'
// 下面的js代码就会按照严格模式执行代码
</script>
<script>
(function() {
'use strict'
}())
</script>
<script>
// 此时只是给fn函数开启严格模式执行
function fn() {
'use strict'
}
function fun() {
// 里面的还是按照普通模式执行
}
</script>
</body>
</html>
严格模式的变化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>严格模式的变化</title>
</head>
<body>
<script>
'use strict'
//1.我们的变量必须先声明再使用
// num = 10;
// console.log(num);
//2.我们不能随意删除已经声明好的变量
// delete num
// console.log(num);
//3.严格模式下全局作用域中函数中的this是undefined
function fn() {
console.log(this);
}
fn() //严格模式下是undefined 普通是window
// 4.严格模式下,如果 构造函数不加new 调用,this指向的是undefined 如果给它赋值则会报错
function Fn(name) {
console.log(this); // 构造函数的this在普通模式下指的是 window
this.name = name
}
var ldh = new Fn('刘德华')
console.log(ldh.name);
//5.定时器 this 还是指向window
setTimeout(function() {
console.log(this); //window
}, 1000)
//a=1;
// a=2
//普通模式下为4
//6.严格模式下函数里面的参数不允许有重名
function math(a, a) {
console.log(a + a);
}
math(1, 2)
</script>
</body>
</html>