1.继承
1.1继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 继承: 一个对象可以去使用另外一个对象的成员
// 继承的好处:有利于代码的复用
/*var lw = {
skill: "*",
age: 28,
sayHi: function () {
}
}
function Person() {}
var xm = new Person();
// 如何实现让xm可以使用到lw对象上的skill属性???
console.log(xm.skill); // ==> **/
// 实现继承的方式
// 1. 原型链继承:实例对象可以直接去访问(继承到了)原型对象上的任意成员
function Person(){
}
Person.prototype.sayHi = function () {
console.log("hi");
}
Person.prototype.running = function () {
console.log("running man");
}
Person.prototype.work = function () {
console.log("work");
}
var p = new Person();
console.log(p);
p.sayHi()
</script>
</body>
</html>
1.2原型链继承-优化写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 实现继承的方式
// 1. 原型链继承:实例对象可以直接去访问(继承到了)原型对象上的任意成员
// function Person(){
// }
/*// 虽然这种写法是可以实现效果的,但是添加的方法过多,写法重复、麻烦
Person.prototype.sayHi = function () {
console.log("hi");
}
Person.prototype.running = function () {
console.log("running man");
}
Person.prototype.work = function () {
console.log("work");
}*/
function Person(){}
// 简化写法 ==> 原型替换
// 问题: constructor属性丢失了
// 解决方案: 给新的原型对象添加constructor属性,指向当前的构造函数
Person.prototype = {
// 手动补上的
constructor: Person,
sayHi: function () {
console.log("hello");
},
work: function () {
console.log("work");
},
running: function () {
console.log("running man");
}
}
var p = new Person();
// 沿着对象的原型链往上查找
// p对象的原型链:
// p ==> Person.prototype({xxxx}) ==> Object.prototype ==> null;
console.log(p.constructor); // Person
/*console.log(p);
p.sayHi()
p.running()*/
// 小结;
// 原型链继承: 给原型对象添加的方法,实例对象是可以直接继承到
// 写法:
// 1. Person.prototype.sayHi = function(){} 问题:添加的方法比较多的时候,写法重复
// 2. 原型替换 Person.prototype = { xxx } 问题: 造成了constructor属性丢失了
// 解决: 手动给新的原型对象添加constructor属性
</script>
</body>
</html>
1.3借用构造函数继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 借用构造函数继承
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
}
function Chinese(name, age, gender, skin) {
// 以下三个name, age, gender属性已经在构造函数Person内写过了
// 如何优化?? ==> 借用构造函数Person来继承里面的属性
// 借用: call apply 作用一样,区别传参
// Person.call(this, name, age, gender);
Person.apply(this, [name, age, gender]);
// 1. call可以调用函数,Person被调用了
// Person函数内的this指向谁?
// Person函数的三个形参的值是什么?
// 2. Person函数内的this指向call的第一个参数, 指向了xm
// 3. call除了第一个参数外,其他所有的参数都是给Person函数传递实参的
/*this.name = name;
this.age = age;
this.gender = gender;*/
this.skin = skin;
}
var xm = new Chinese("xm", 20, "male", "黄");
console.log(xm);
</script>
</body>
</html>
1.4组合继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 组合继承:
// 1. 原型链继承 ==> 继承到Person的prototype上的方法
// 2. 借用构造函数继承 ==> 继承到Person构造函数内添加的属性
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.sayHi = function () {
console.log("hello, 我是 " + this.name);
}
function Chinese(name, age, gender, skin) {
// 借用构造函数继承 ==> 继承到name、age。gender属性
Person.apply(this, [name, age, gender]);
this.skin = skin;
}
// 原型链继承 ==> 原型替换写法
Chinese.prototype = Person.prototype;
// 演示以上原型替换写法的问题:
// 想要修改Chinese.prototype,其实本质上修改了Person.prototype
Chinese.prototype.color = "lime";
// 想要给Chinese.prototype添加sayHi方法,但是本质上是修改了Person.prototype原型对象上的sayHi方法。
Chinese.prototype.sayHi = function () {
console.log("hi");
}
var xm = new Chinese("xm", 20, "male", "黄");
console.log(xm);
// xm去使用sayHi方法,沿着xm的原型链来找方法。
// xm的原型链:
// xm ==> Chinese.prototype(本质上Person.prototype) ==> Object.prototype ==> null;
// 核心的点: 让Person的prototype出现在xm的原型链上
// 把Chinese的prototype换成Person的prototype
xm.sayHi();
</script>
</body>
</html>
1.5组合继承-优化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 组合继承:
// 1. 原型链继承 ==> 继承到Person的prototype上的方法
// 2. 借用构造函数继承 ==> 继承到Person构造函数内添加的属性
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.sayHi = function () {
console.log("hello, 我是 " + this.name);
}
function Chinese(name, age, gender, skin) {
// 借用构造函数继承 ==> 继承到name、age。gender属性
Person.apply(this, [name, age, gender]);
this.skin = skin;
}
// 原型链继承 ==> 原型替换写法
// Chinese.prototype = Person.prototype;
/*var p = new Person(); // p 是Person的实例对象
Chinese.prototype = p;*/
// 上面两行代码的简化写法
Chinese.prototype = new Person();// p 是Person的实例对象
Chinese.prototype.color = "lime"; // 本质上其实是修改了p
// xm的原型链:
// xm ==> Chinese.prototype(本质上实例对象p)==> Person.prototype ==> Object.prototype ==> null;
var xm = new Chinese("xm", 20, "male", "黄");
console.log(xm);
// 优化后的效果
// 1. xm还可以继续使用sayHi方法
// 2. 修改Chinese.prototype,不会影响到Person.prototype
// xm去使用sayHi方法,沿着xm的原型链来找方法。
// 核心的点: 让Person的prototype出现在xm的原型链上
// 把Chinese的prototype换成Person的prototype
xm.sayHi();
</script>
</body>
</html>
2.类
2.1ES6的class
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 继承 ES6 class类 类的继承很简单
/*function Person(){}
var p = new Person();*/
/*// 类的语法 class 类{}
class Person{}
// 通过类来创建实例对象, new 类()
var p = new Person();
console.log(p);*/
// 给类的实例对象添加属性 ==> 在类的内部通过constructor函数来进行添加
class Person{
constructor(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
// 如此添加方法可以,但是容易造成内存浪费问题
// 要添加方法,需要给原型对象添加
/*this.sayHi = function () {
console.log("hi");
}*/
}
// 在类的{}里面写的方法,是添加在原型对象上了
sayHi() {
console.log("hello");
}
work(){
console.log("work save money");
}
}
var p = new Person("xm", 20, "male");
console.log(p);
p.sayHi();
p.work();
// ES6 类 创建对象
// 定义:class 类{}
// 创建实例: new 类();
// 给类的实例添加属性: 类的内部通过constructor函数来添加
// 给类的实例添加方法: 给原型对象上添加,把方法直接写在类的里面
/*class Chinese {
constructor(){
// 实例添加属性
}
// 给原型对象添加方法
sayHi(){//...}
}*/
// 类 语法糖
// 类的本质还是构造函数 + 原型对象
</script>
</body>
</html>
2.2类的继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 类的继承语法:
// class 子类 extends 父类{}
// 父类
class Person {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
sayHi() {
console.log("hello");
}
}
// 子类
// 子类是继承到父类上的属性和原型上的方法
class Chinese extends Person {
// 处理skin属性 ==> 需要在constructor函数内来添加
/*constructor(name, age, gender, skin){
// 在子类的constructor函数中,必须优先调用super();
// super函数表示的是父类的构造函数
super(name, age, gender);
this.skin = skin;
}*/
constructor(name, age, gender, skin) {
// 只要在子类中, 写了constructor函数,必须去做: 在constructor函数内优先去调用super函数
super(name, age, gender);
this.skin = skin;
}
}
// 实例化子类
var p = new Chinese("xm", 20, "male", "黄");
console.log(p);
p.sayHi();
// 小结:
// 类的继承语法: class 子类 extends 父类
// 子类就已经继承到父类的属性和原型上的方法
// 子类中添加自己的属性,写constructor构造函数
// 注意点: 必须优先调用super函数(父类的构造函数)
// 然后在去添加自己的属性
</script>
</body>
</html>