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 = name this.age = age } // 2.实例方法 // 本质上是放在Person.prototype running() { 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 = name this.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 = name this.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 = x this.y = y this.width = width this.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 = name this.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 = name this.age = age } running() { console.log("running~") } eating() { console.log("eating~") } } class Student extends Person { constructor(name, age, sno, score) { // this.name = name // this.age = age super(name, age) this.sno = sno this.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 = age super(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 = width this.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 = 123 foo = "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 = 18 var 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"] = names console.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 = "中国" } = obj console.log(wName, wAge, wHeight, wAddress) // 2.5. 对象的剩余内容 var { name, age, ...newObj } = obj console.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.prototype function foo(name, age) { console.log(this, name, age) } // foo函数可以通过apply/call // foo.apply("aaa", ["why", 18]) // foo.call("bbb", "kobe", 30) // 1.给函数对象添加方法: hyapply Function.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 = this Object.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.给函数对象添加方法: hycall Function.prototype.hycall = function(thisArg, ...otherArgs) { // 1.获取thisArg, 并且确保是一个对象类型 thisArg = (thisArg === null || thisArg === undefined)? window: Object(thisArg) // thisArg.fn = this Object.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.prototype function 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 = this Object.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 = this Object.defineProperty(thisArg, "fn", { enumerable: false, configurable: true, value: this }) thisArg.fn(...otherArgs) delete thisArg.fn } // 1.给函数对象添加方法: hyapply Function.prototype.hyapply = function(thisArg, otherArgs) { this.hyexec(thisArg, otherArgs) } // 2.给函数对象添加方法: hycall Function.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/call function 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>