<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
<title>哈哈 - </title>
</head>
<body>
</body>
</html>
<script>
/*
* JS本身是基于面向对象开发的编程语言
* => 类:封装、继承、多态
*
* 封装:类也是一个函数,把实现一个功能的代码进行封装,以此实现“低耦合高内聚”
* 多态:重载、重写
* 重写:子类重写父类上的方法(伴随着继承运行的)
* 重载:相同的方法,由于参数或者返回值不同,具备了不同的功能(JS中不具备严格意义上的重载,JS中的重载:同一个方法内,根据传参不同实现不同的功能)
* 继承:子类继承父类中的方法
*/
/*
public void fn(int x, init y){}
public void fn(int x){ }
JavaScript中:
fn(10, 20); 执行第一个FN
fn(10); 执行第二个FN
fn('哈哈'); 报错
*/
function fn(x, y) {
console.log(x, y)
}
function fn(x) {
console.log(x)
}
fn(10, 20); // 执行第二个FN
fn(10); // 执行第二个FN
function fn(x, y) {
if (y === undefined) {
// ...
return;
}
// ....
}
fn(10);
fn(10, 20);
</script>
<script>
/*
* 在JS语言中,它的继承和其它编程语言还是不太一样的
* 继承的目的:让子类的实例同时也具备父类中的私有属性和公共方法
*/
// JS中第一种继承方案:原型继承(让子类的原型等于父类的实例即可)
function Parent() {
this.x = 100;
}
Parent.prototype.getX = function getX() {
return this.x;
};
function Child() {
this.y = 200;
}
// => 原型继承
Child.prototype = new Parent;
// console.log(Child.prototype.constructor) // 改变了Child.prototype.constructor指向:ƒ Parent() {this.x = 100;},应该重新指向Child
Child.prototype.getY = function getY() {
return this.y;
};
let c1 = new Child;
console.log(c1); // Child {y: 200}
console.log(c1.y); // 200
console.log(c1.x); // 100
console.log(c1.getY()); // 200
console.log(c1.getX()); // 100
// -----------------------------------
// JS中第二种继承方式:CALL继承(只能继承父类中私有的,不能继承父类中公共的)
function Parent() {
this.x = 100;
}
Parent.prototype.getX = function getX() {
return this.x;
};
function Child() {
// 在子类构造函数中,把父类当做普通方法执行(没有父类实例,父类原型上的那些东西也就和它没关系了)
// this -> Child的实例c1
Parent.call(this); // this.x=100: 相当于强制给c1这个实例设置一个私有的属性x,属性值100,相当于让子类的实例继承了父类的私有的属性,并且也变为了子类私有的属性 “拷贝式”
this.y = 200;
}
Child.prototype.getY = function getY() {
return this.y;
};
let c1 = new Child;
console.log(c1);
// -----------------------------------
// 我们满意的:父类私有的,变成子类私有的;父类公共的,变成子类公共的。
// JS中第三种继承:寄生组合式继承(CALL继承 + 另类原型继承)
function Parent() {
this.x = 100;
}
Parent.prototype.getX = function getX() {
return this.x;
};
function Child() {
Parent.call(this);
this.y = 200;
}
Child.prototype = Object.create(Parent.prototype);
// 重定向了Child.prototype,重新指向Child
Child.prototype.constructor = Child;
Child.prototype.getY = function getY() {
return this.y;
};
let c1 = new Child;
console.log(c1);
// 创建一个空对象,让其原型链指向obj
/* let obj = {
xxx: 'xxx'
};
console.log(Object.create(obj)); */
</script>
<script>
/* ES6中的类和继承 */
class Parent {
constructor() {
this.x = 100;
}
// Parent.prototype.get X = function... ,在Parent.prototype上添加方法getX
getX() {
return this.x;
}
}
// 继承: extends Parent(类似于寄生组合继承)
// 注意:继承后,【如果子类有constructor,】一定要在constructor第一行加上super
class Child extends Parent {
constructor() {
// 类似于我们之前的CALL继承。super(100,200):相当于把Parent中的constructor执行,传递了100和200
super();
this.y = 200;
}
getY() {
return this.y;
}
}
let c1 = new Child;
console.log(c1);
// Child(); // => Uncaught TypeError: Class constructor Child cannot be invoked without 'new' : ES6中创建的就是类,不能当做普通函数执行,只能new执行
</script>
// 补充案例
function wjl(name, age) {
// name、age通过参数传进来的,是每一个实例对象私有的属性。
// height、house不是通过参数传进来的,是所有实例对象共有的属性。
this.name = name
this.age = age
this.height = 188
this.house = function () {
return '兰博基尼'
}
}
wjl.prototype.money = 888
var obj = new wjl('王健林', 12) // obj是wjl的实例对象, 参数 '王健林'、12是obj这个实例对象私有的,不是wjl所有的实例对象共有,这里的 '王健林'、12 和 wsc的实例对象o 没有关系
console.log('obj-------', obj) // wjl {name: "王健林", age: 12, height: 188, house: ƒ}
function wsc(names, ages) {
this.names = names
this.ages = ages
wjl.call(this) // 继承wjl,而不是wjl的实例
}
var o = new wsc('王思聪', 22, 33, 55)
console.log('o----', o) // wsc {names: "王思聪", ages: 22, name: undefined, age: undefined, height: 188, …}
// 【'王健林'、12是obj实例的私有属性,不是wjl类的所有实例继承的属性。如果在wjl类中写 this.height = 188,而不是传进来的参数,那么this.height = 188就是wjl类的所有实例继承的属性、属性值,就像wjl类的this.house。】
console.log(o.house, o.name, o.age) // 函数 undefined undefined
console.log(o.house, o.names, o.ages) // 函数 王思聪 22