1 对象的方法补充
2 原型继承关系图
3 class方式定义类
4 extends实现继承
5 extends实现继承
6 多态概念的理
function 创建的名称如果开头是大写的,那这个创建的不是函数,是创建了类。
ES6-class类中的内容
<!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>var obj = {running: function() {},eating: () => {},swimming() {}}// function Person() {// }// Person.prototype.running = function() {// }// 编程: 高内聚低耦合class Person {// 1.类中的构造函数// 当我们通过new关键字调用一个Person类时, 默认调用class中的constructor方法constructor(name, age) {this.name = namethis.age = age}// 2.实例方法// 本质上是放在Person.prototyperunning() {console.log(this.name + " running~")}eating() {console.log(this.name + " eating~")}}// 创建实例对象var p1 = new Person("why", 18)// 使用实例对象中属性和方法console.log(p1.name, p1.age)p1.running()p1.eating()// 研究内容console.log(Person.prototype === p1.__proto__)console.log(Person.running) // 不能调用console.log(Person.prototype.running) // 可以调用</script></body> </html>
ES6-class和function类的区别
可以把class创建的类当做是function创建的类的一种语法糖。但是在直接使用的方面是有不同之处。类里面的方法又叫静态方法。
<!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>// function定义类function Person1(name, age) {this.name = namethis.age = age}Person1.prototype.running = function() {}Person1.prototype.eating = function() {}var p1 = new Person1("why", 18)console.log(p1.__proto__ === Person1.prototype)console.log(Person1.prototype.constructor)console.log(typeof Person1) // function// 不同点: 作为普通函数去调用Person1("abc", 100)// class定义类class Person2 {constructor(name, age) {this.name = namethis.age = age}running() {}eating() {}}var p2 = new Person2("kobe", 30)console.log(p2.__proto__ === Person2.prototype)console.log(Person2.prototype.constructor)console.log(typeof Person2)// 不同点: class定义的类, 不能作为一个普通的函数进行调用Person2("cba", 0)</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>Document</title> </head> <body><script>// 针对对象// 方式一: 描述符// var obj = {// _name: "why"// }// Object.defineProperty(obj, "name", {// configurable: true,// enumerable: true,// set: function() {// },// get: function() {// }// })// 方式二: 直接在对象定义访问器// 监听_name什么时候被访问, 什么设置新的值var obj = {_name: "why",// setter方法set name(value) {this._name = value},// getter方法get name() {return this._name}}obj.name = "kobe"console.log(obj.name)</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>Document</title> </head> <body><script>// 1.访问器的编写方式// class Person {// // 程序员之间的约定: 以_开头的属性和方法, 是不在外界访问// constructor(name, age) {// this._name = name// }// set name(value) {// console.log("设置name")// this._name = value// }// get name() {// console.log("获取name")// return this._name// }// }// var p1 = new Person("why", 18)// p1.name = "kobe"// console.log(p1.name)// // console.log(p1._name)// var p2 = new Person("james", 25)// console.log(p2.name)// 2.访问器的应用场景class Rectangle {constructor(x, y, width, height) {this.x = xthis.y = ythis.width = widththis.height = height}get position() {return { x: this.x, y: this.y }}get size() {return { width: this.width, height: this.height }}}var rect1 = new Rectangle(10, 20, 100, 200)console.log(rect1.position)console.log(rect1.size)</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>Document</title> </head> <body><script>// function Person() {}// // 实例方法// Person.prototype.running = function() {}// // 类方法// Person.randomPerson = function() {}// var p1 = new Person()// p1.running()// Person.randomPerson()// class定义的类var names = ["abc", "cba", "nba", "mba"]class Person {constructor(name, age) {this.name = namethis.age = age}// 实例方法running() {console.log(this.name + " running~")}eating() {}// 类方法(静态方法)static randomPerson() {console.log(this)var randomName = names[Math.floor(Math.random() * names.length)]return new this(randomName, Math.floor(Math.random() * 100))}}var p1 = new Person()p1.running()p1.eating()var randomPerson = Person.randomPerson()console.log(randomPerson)</script></body> </html>
ES6-通过extends实现继承
<!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>// 定义父类class Person {constructor(name, age) {this.name = namethis.age = age}running() {console.log("running~")}eating() {console.log("eating~")}}class Student extends Person {constructor(name, age, sno, score) {// this.name = name// this.age = agesuper(name, age)this.sno = snothis.score = score}// running() {// console.log("running~")// }// eating() {// console.log("eating~")// }studying() {console.log("studying~")}}var stu1 = new Student("why", 18, 111, 100)stu1.running()stu1.eating()stu1.studying()class Teacher extends Person {constructor(name, age, title) {// this.name = name// this.age = agesuper(name, age)this.title = title}// running() {// console.log("running~")// }// eating() {// console.log("eating~")// }teaching() {console.log("teaching~")}}</script></body> </html>
ES6-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>Document</title> </head> <body><script>class Animal {running() {console.log("running")}eating() {console.log("eating")}static sleep() {console.log("static animal sleep")}}class Dog extends Animal {// 子类如果对于父类的方法实现不满足(继承过来的方法)// 重新实现称之为重写(父类方法的重写)running() {console.log("dog四条腿")// 调用父类的方法super.running()// console.log("running~")// console.log("dog四条腿running~")}static sleep() {console.log("趴着")super.sleep()}}var dog = new Dog()dog.running()dog.eating()Dog.sleep()</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>Document</title> </head> <body><script>// 1.创建一个新的类, 继承自Array进行扩展class HYArray extends Array {get lastItem() {return this[this.length - 1]}get firstItem() {return this[0]}}var arr = new HYArray(10, 20, 30)console.log(arr)console.log(arr.length)console.log(arr[0])console.log(arr.lastItem)console.log(arr.firstItem)// 2.直接对Array进行扩展Array.prototype.lastItem = function() {return this[this.length - 1]}var arr = new Array(10, 20, 30)console.log(arr.__proto__ === Array.prototype)console.log(arr.lastItem())// 函数apply/call/bind方法 -> Function.prototype</script></body> </html>
ES6-类的混入mixin的用法
<!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>// JavaScript只支持单继承(不支持多继承)function mixinAnimal(BaseClass) {return class extends BaseClass {running() {console.log("running~")}}}function mixinRunner(BaseClass) {return class extends BaseClass {flying() {console.log("flying~")}}}class Bird {eating() {console.log("eating~")}}// var NewBird = mixinRunner(mixinAnimal(Bird))class NewBird extends mixinRunner(mixinAnimal(Bird)) {}var bird = new NewBird()bird.flying()bird.running()bird.eating()</script></body> </html>
ES6-ES6中的class转ES5代码
<!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>// class Person {// constructor(name, age) {// this.name = name// this.age = age// }// running() {}// eating() {}// static randomPerson() {}// }// var p1 = new Person()</script><script src="./js/es5_code01.js"></script></body> </html>
可以去babel官网打开try out,然后改default。
ES6-Java面向对象的多态理解
<!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>// 继承是多态的前提// shape形状class Shape {getArea() {}}class Rectangle extends Shape {constructor(width, height) {super()this.width = widththis.height = height}getArea() {return this.width * this.height}}class Circle extends Shape {constructor(radius) {super()this.radius = radius}getArea() {return this.radius * this.radius * 3.14}}var rect1 = new Rectangle(100, 200)var rect2 = new Rectangle(20, 30)var c1 = new Circle(10)var c2 = new Circle(15)// 表现形式就是多态/*在严格意义的面向对象语言中, 多态的是存在如下条件的:1.必须有继承(实现接口)2.必须有父类引用指向子类对象*/function getShapeArea(shape) {console.log(shape.getArea())}getShapeArea(rect1)getShapeArea(c1)var obj = {getArea: function() {return 10000}}getShapeArea(obj)getShapeArea(123)</script></body> </html>
ES6-JS面向对象的多态理解
<!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>// 多态的表现: JS到处都是多态function sum(a1, a2) {return a1 + a2}sum(20, 30)sum("abc", "cba")// 多态的表现var foo = 123foo = "Hello World"console.log(foo.split())foo = {running: function() {}}foo.running()foo = []console.log(foo.length)</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>Document</title> </head> <body><script>/*1.属性的增强2.方法的增强3.计算属性名的写法*/var name = "why"var age = 18var key = "address" + " city"var obj = {// 1.属性的增强name,age,// 2.方法的增强running: function() {console.log(this)},swimming() {console.log(this)},eating: () => {console.log(this)},// 3.计算属性名[key]: "广州"}obj.running()obj.swimming()obj.eating()function foo() {var message = "Hello World"var info = "my name is why"return { message, info }}var result = foo()console.log(result.message, result.info)</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>Document</title> </head> <body><script>var names = ["abc", "cba", undefined, "nba", "mba"]// 1.数组的解构// var name1 = names[0]// var name2 = names[1]// var name3 = names[2]// 1.1. 基本使用// var [name1, name2, name3] = names// console.log(name1, name2, name3)// 1.2. 顺序问题: 严格的顺序// var [name1, , name3] = names// console.log(name1, name3)// 1.3. 解构出数组// var [name1, name2, ...newNames] = names// console.log(name1, name2, newNames)// 1.4. 解构的默认值var [name1, name2, name3 = "default"] = namesconsole.log(name1, name2, name3)// 2.对象的解构var obj = { name: "why", age: 18, height: 1.88 }// var name = obj.name// var age = obj.age// var height = obj.height// 2.1. 基本使用// var { name, age, height } = obj// console.log(name, age, height)// 2.2. 顺序问题: 对象的解构是没有顺序, 根据key解构// var { height, name, age } = obj// console.log(name, age, height)// 2.3. 对变量进行重命名// var { height: wHeight, name: wName, age: wAge } = obj// console.log(wName, wAge, wHeight)// 2.4. 默认值var { height: wHeight, name: wName, age: wAge, address: wAddress = "中国"} = objconsole.log(wName, wAge, wHeight, wAddress)// 2.5. 对象的剩余内容var {name,age,...newObj} = objconsole.log(newObj)// 应用: 在函数中(其他类似的地方)// function getPosition(position)直接把position解构成{ x, y },方便拿对象里面的参数function getPosition({ x, y }) {console.log(x, y)}getPosition({ x: 10, y: 20 })getPosition({ x: 25, y: 35 })function foo(num) {}foo(123)</script></body> </html>
补充-手写apply-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>Document</title> </head> <body><script>// new Function()// foo.__proto__ === Function.prototypefunction foo(name, age) {console.log(this, name, age)}// foo函数可以通过apply/call// foo.apply("aaa", ["why", 18])// foo.call("bbb", "kobe", 30)// 1.给函数对象添加方法: hyapplyFunction.prototype.hyapply = function(thisArg, otherArgs) {// this -> 调用的函数对象// thisArg -> 传入的第一个参数, 要绑定的this// console.log(this) // -> 当前调用的函数对象// this.apply(thisArg)thisArg.fn = this// 1.获取thisArg, 并且确保是一个对象类型thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)// thisArg.fn = thisObject.defineProperty(thisArg, "fn", {enumerable: false,configurable: true,value: this})thisArg.fn(...otherArgs)delete thisArg.fn}// foo.hyapply({ name: "why" }, ["james", 25])// foo.hyapply(123, ["why", 18])// foo.hyapply(null, ["kobe", 30])// 2.给函数对象添加方法: hycallFunction.prototype.hycall = function(thisArg, ...otherArgs) {// 1.获取thisArg, 并且确保是一个对象类型thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)// thisArg.fn = thisObject.defineProperty(thisArg, "fn", {enumerable: false,configurable: true,value: this})thisArg.fn(...otherArgs)delete thisArg.fn}foo.hycall({ name: "why", fn: "abc" }, "james", 25)foo.hycall(123, "why", 18)foo.hycall(null, "kobe", 30)</script></body> </html>
补充-手写apply-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>Document</title> </head> <body><script>// new Function()// foo.__proto__ === Function.prototypefunction foo(name, age) {console.log(this, name, age)}// foo函数可以通过apply/call// foo.apply("aaa", ["why", 18])// foo.call("bbb", "kobe", 30)// 1.封装思想// 1.1.封装到独立的函数中function execFn(thisArg, otherArgs, fn) {// 1.获取thisArg, 并且确保是一个对象类型thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)// thisArg.fn = thisObject.defineProperty(thisArg, "fn", {enumerable: false,configurable: true,value: fn})// 执行代码thisArg.fn(...otherArgs)delete thisArg.fn}// 1.2. 封装原型中Function.prototype.hyexec = function(thisArg, otherArgs) {// 1.获取thisArg, 并且确保是一个对象类型thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg)// thisArg.fn = thisObject.defineProperty(thisArg, "fn", {enumerable: false,configurable: true,value: this})thisArg.fn(...otherArgs)delete thisArg.fn}// 1.给函数对象添加方法: hyapplyFunction.prototype.hyapply = function(thisArg, otherArgs) {this.hyexec(thisArg, otherArgs)}// 2.给函数对象添加方法: hycallFunction.prototype.hycall = function(thisArg, ...otherArgs) {this.hyexec(thisArg, otherArgs)}foo.hyapply({ name: "why" }, ["james", 25])foo.hyapply(123, ["why", 18])foo.hyapply(null, ["kobe", 30])foo.hycall({ name: "why" }, "james", 25)foo.hycall(123, "why", 18)foo.hycall(null, "kobe", 30)</script></body> </html>
补充-手写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>Document</title> </head> <body><script>// apply/callfunction foo(name, age, height, address) {console.log(this, name, age, height, address)}// Function.prototype// var newFoo = foo.bind({ name: "why" }, "why", 18)// newFoo(1.88)// 实现hybind函数Function.prototype.hybind = function(thisArg, ...otherArgs) {// console.log(this) // -> foo函数对象thisArg = thisArg === null || thisArg === undefined ? window: Object(thisArg)Object.defineProperty(thisArg, "fn", {enumerable: false,configurable: true,writable: false,value: this})return (...newArgs) => {// var allArgs = otherArgs.concat(newArgs)var allArgs = [...otherArgs, ...newArgs]thisArg.fn(...allArgs)}}var newFoo = foo.hybind("abc", "kobe", 30)newFoo(1.88, "广州市")newFoo(1.88, "广州市")newFoo(1.88, "广州市")newFoo(1.88, "广州市")</script></body> </html>