1.1-面向对象三大特征介绍
- 封装:将某个具体功能封装在对象中,只对外部暴露指定接口,外界在使用的时候,只考虑接口怎么用,不用考虑内部怎么实现(前面学习的api其实就是一种封装思想)
- b.继承:一个对象拥有其他对象的属性和方法
- c.多态:一个对象在不同情况下的多种状态(java语言使用较多,js语言基本不涉及)
1.2-替换原型继承
继承:让一个对象拥有另一个对象的属性和方法
原型继承 :把父对象作为子对象构造函数的原型
/* 替换原型继承: 把父对象作为子对象构造函数的原型*/
Son.prototype = father
//父对象
let father = {
house: {
address: '深圳湾一号',
price: 20000000
},
car: {
brand: '劳斯莱斯幻影',
price: 15000000
}
}
//子对象
//构造函数
function Son(name, age) {
this.name = name
this.age = age
}
//原型继承: 把父对象 作为子对象构造函数的原型
Son.prototype = father
//可选 : 原型继承之后,由于父对象覆盖原来的 子对象构造函数原型, 就会导致constructor消失.
//解决办法: 手动添加。(对开发几乎没有影响,也可以不加)
Son.prototype.constructor = Son
//实例对象
let s1 = new Son('ikun', 30)
let s2 = new Son('班长', 20)
console.log(s1, s2)
02-原型链
==1.1-原型链介绍==
- 1.原型链:每一个对象都有原型,原型本身又是对象,所以原型又有原型,以此类推形成一个链式结构,称为原型链
2.对象访问原型链中的成员规则:就近原则
对象先访问自己的,自己没有就找原型的,原型没有就找原型的原型,一直到原型链终点null.如果还找不到。 属性则获取undefined, 方法则会报错 xxx is not function
xxx is not a function
//1.构造函数
function Person(name,age){
this.name = name
this.age = age
// this.type = '学生'//如果自己有type,优先访问自己的
}
//2.原型对象 : 存储具有共同特征的数据
Person.prototype.type = '哺乳动物'
Person.prototype.country = '中国'
Person.prototype.eat = function(){
console.log(this.name + '吃东西')
}
//3.实例对象
let p1 = new Person('班长',20)
let p2 = new Person('ikun',20)
console.log(p1)
/* 小测试 */
console.log( p1.name )//班长 p1自己有name属性
console.log( p1.age )//20 p1自己有age
console.log( p1.type )//哺乳动物 p1自己没有type,但是p1的原型有
console.log( p1.girlFrined )//undefined p1自己没有girlFrined, p1的原型也没有girlFrined
p1.eat()// 吃东西
// p1.learn()//报错 undefined is not a function
/* 思考: p1自己没有toString, p1的原型也没有toString, 但是为什么不报错呢?
原因: p1的原型的原型有toString
*/
p1.toString()
/* 如何查看实例对象原型 : 两行 */
//查看p1的原型
console.log( p1.__proto__.constructor )//Person
console.log( Person.prototype === p1.__proto__ )//true
//查看p1的原型的原型
console.log( p1.__proto__.__proto__.constructor )//Object
console.log( Object.prototype === p1.__proto__.__proto__ )//true
//查看p1的原型的原型的原型
console.log( p1.__proto__.__proto__.__proto__ )//null
1.2-原型链详解:内置对象的原型链
- 本小节知识点:内置对象的原型链(附图解说明)
-
- 1.通过查看Array的原型链
-
- 了解构造函数的原型本身是一个对象,只要是对象就有原型
- 2.通过查看Date的原型链
-
- 学会举一反三,所有的内置对象(Math Array 基本包装类型等)的原型链都是一样的,最终都指向Object
- 3.通过查看String的原型链:了解这里的String值得是内置对象String(是一个基本包装类型),其他的Number、Boolean原型链和String是一样的
-
- 只有对象才有原型,这里一定要把基本数据类型string、number、boolean,和基本包装类型(特殊的引用类型对象)String、Number、Boolean区分开来,不要搞混淆
1.Array的原型链
// 数组对象
//实例化对象
let arr = [10,20,30]//new Array(10,20,30)
console.log( arr )
//1.1 查看arr的原型
console.log( arr.__proto__.constructor )//Array
console.log( arr.__proto__ === Array.prototype )//true
//1.2 查看arr的原型的原型
console.log( arr.__proto__.__proto__.constructor )//Object
console.log( arr.__proto__.__proto__ === Object.prototype )//true
// 字符串对象
let str = new String('abc')
console.log( str )
//2.1 查看str的原型
console.log( str.__proto__.constructor )//String
console.log( str.__proto__ === String.prototype )//true
//2.2 查看arr的原型的原型
console.log( str.__proto__.__proto__.constructor )//Object
console.log( str.__proto__.__proto__ === Object.prototype )//true
// 日期对象
let date = new Date()
/* js有几个特殊的对象 无法使用 log来打印的,需要用dir来打印: function date dom对象 */
console.dir( date )
//3.1 查看date的原型
console.log( date.__proto__.constructor )//Date
console.log( date.__proto__ === Date.prototype )//true
//3.2 查看date的原型的原型
console.log( date.__proto__.__proto__.constructor )//Object
console.log( date.__proto__.__proto__ === Object.prototype )//true
2-Date的原型链
<div>我是div</div>
<p>我是pp</p>
<a href="#">我是aa</a>
<script>
let div = document.querySelector('div')
let p = document.querySelector('p')
let a = document.querySelector('a')
3-String对象原型链
//4.界面元素 let div1 = document.getElementById('div1'); let p1 = document.getElementById('p1');
完整代码
1.3-instanceof运算符
instanceof语法: 对象 instanceof 构造函数
作用:检测构造函数的原型prototype在不在这个对象的原型链上
- instanceof(关键字): 运算符。 用于检测 构造函数的prototype在不在实例对象的原型链中
说人话: 亲子鉴定,鉴定两个对象之间有没有血缘关系
- 实例对象 instanceof 构造函数
检测 右边构造函数的prototype 在不在 左边实例对象的原型链中
- 应用 : 某些函数为了限制你的数据类型,在内部需要用instanceof进行判断是否是正确的数据类型
let arr = [10,20,30]
// arr-> Array.prototype -> Object.prototype -> null
console.log( arr instanceof Array )//true
console.log( arr instanceof Object )//true
console.log( arr instanceof String )//false
//封装一个函数,要求这个函数必须要传数组类型、 传其他类型不可以
function fn(arr){
if( arr instanceof Array){
console.log( arr.reverse() )
}else{
console.log('数据类型错误')
}
}
fn( [10,20,30] )
fn( 'abc' )
03-ES6类与继承
1.1-class关键字介绍
1.1 class关键字作用: 声明一个类函数
-
相当于ES5的构造函数,只是代码的阅读性大大提高
-
a. 把构造函数和原型全部写在一个大括号里面,提高代码阅读性
-
b. 必须要使用new才可以调用class函数,提高代码规范
1.2 class关键字语法:
class 构造函数名{
constructor(){
//(1)这里写构造函数代码
};
//(2)原型里面的方法写在下面
eat(){
};
play(){
};
};
2.学习路线:对比法
2.1 ES5 构造函数与原型语法
2.2 ES6 构造函数与原型语法
*/
//1.ES5得构造函数与原型写法
// //(1)构造函数
// function Person(name,age){
// this.name = name;
// this.age = age;
// };
// //(2)给原型添加方法
// Person.prototype.eat = function(){
// console.log('大吉大利今晚吃鸡');
// };
// Person.prototype.sayHi = function(){
// console.log('你好,我是四大天王黎明');
// };
// //(3)实例对象
// let p1 = new Person('ikun',30);
// console.log(p1);
//2. ES6的构造函数写法
//(1)声明类Person
class Person {
//(1) 构造函数 : 名字必须叫做 constructor
constructor(name, age) {
this.name = name;
this.age = age;
};
//(2) 给原型添加方法 : 方法名(){}
sayHi() {
console.log('你好,我是四大天王黎明');
};
eat() {
console.log('大吉大利今晚吃鸡');
};
};
/* 细节: class本质其实就是构造函数的另一种写法,本质还是给prototype添加成员
使用了class,一样可以继续使用ES5的prototype
*/
Person.prototype.type = '人类';
//(3)实例对象
let p1 = new Person('ikun', 30);
console.log(p1);
1.2-extends关键字介绍
学习目标: extends关键字
1.作用: 继承
2.底层原理: 替换原型继承
*/
//(1)声明类Person
class Person {
//(1) 构造函数 : 名字必须叫做 constructor
constructor(name, age) {
this.name = name;
this.age = age;
};
//(2) 给原型添加方法 : 方法名(){}
sayHi() {
console.log('你好,我是四大天王黎明');
};
eat() {
console.log('大吉大利今晚吃鸡');
};
};
Person.prototype.type = '人类';
//(3)实例对象
let p1 = new Person('ikun', 30);
console.log(p1);
/* extends关键字 */
//声明一个类函数 Student 继承于 Person 类函数
//底层原理相当于 Student.prototype.__proto__ = Person.prototype
class Student extends Person{
//Student原型添加方法
learn(){
console.log('今天学的很开心');
};
};
let s1 = new Student('班长',20);
console.log(s1);
s1.learn();//s1自己没有learn,但是原型有
s1.eat();//s1自己没有eat,原型没有eat, 但是原型的原型有eat
1.3-super关键字介绍
/*
学习目标: super关键字
1.作用: 子类中调用父类的方法
2.底层原理: 函数上下文调用
*/
//(1)声明类Person
class Person {
//(1) 构造函数 : 名字必须叫做 constructor
constructor(name, age) {
this.name = name;
this.age = age;
};
//(2) 给原型添加方法 : 方法名(){}
sayHi() {
console.log('你好,我是四大天王黎明');
};
eat() {
console.log('大吉大利今晚吃鸡');
};
};
Person.prototype.type = '人类';
//(3)实例对象
let p1 = new Person('ikun', 30);
console.log(p1);
/* super关键字 : 子类中调用父类的方法
如果在子类中,也写了 constructor函数,则必须要调用 super()否则程序报错
*/
/* 声明子类Student 继承 父类 Person */
class Student extends Person{
//子类构造函数
constructor(name,age,score){
/* 注意点:如果子类也写了constructor,则必须要调用super */
super(name,age);
this.score = score;
}
//Student原型添加方法
learn(){
console.log('1.我要吃饭了');
//调用Person原型中的eat()
//底层原理: Person.call(this)
super.eat();
console.log('3.我开始学习了');
};
};
let s1 = new Student('班长',20,99);
console.log(s1);
s1.learn();//s1自己没有learn,但是原型有
s1.eat();//s1自己没有eat,原型没有eat, 但是原型的原型有eat
04-函数补充(了解即可)
1.1-arguments关键字
1.arguments关键字: 获取函数所有实参
-
是一个伪数组
-
只能用于函数
2.场景 : 例如数组push()方法,传多少实参就给数组添加多少元素。底层原理就是使用arguments实现的
function fn(){
console.log(arguments)
}
fn(10,20,30,40)
1.2-剩余参数(rest参数)
1.剩余参数(rest参数) : 获取函数剩余的所有实参
-
是一个真数组
-
只能写在函数最后形参位置
2.场景:大多数情况下, rest参数可以替代arguments
arguments是老语法,浏览器兼容性好
rest参数:新语法,有些老的浏览器不支持
function fn(a,b,...c){
console.log(arguments)//获取所有实参 10 20 30 40
console.log(a,b)//10 20
console.log(c)//[30,40] 获取剩余参数
}
fn(10,20,30,40)
1.3-函数默认参数
/*函数默认参数
ES5 : 逻辑或短路
-
逻辑或口诀: 一真则真
-
逻辑或短路口诀 : 找真. 左边为真就是左边的结果,否则右边的结果
ES6 : 形参=默认值
function fn(a, b = 20) {
// b = b || 20
console.log(a)
console.log(b)//如果b是undefined, 则 a + b = NaN
//10 + Number(undefined) = 10 + NaN = NaN
console.log(a + b)
}
fn(10,5)
fn(10)
今日学习总结
- 1.面向对象三大特征
-
- a.封装:将某个功能封装到对象或函数中
- b.继承:一个对象拥有另一个对象的所有成员变量(属性和方法)
- c.多态:一个对象在不同情况的多种状态
- 2.实现继承的几种方式
-
- a.混入式继承
-
- 解决方案:遍历父对象的所有属性值,添加给子对象
- 弊端:每继承一次,就要执行一次循环
- 应用场景:父对象只有一个子对象
- b.替换原型
-
- 解决方案:将父对象作为子对象构造函数的原型
- 弊端:会丢失原型之前的成员变量
- 应用场景:自定义内置对象
- c.混合式(混入+替换原型)
-
- 解决方案:遍历父对象所有的属性值,添加给构造函数的原型
- 应用场景:父对象有多个子对象
- 3.原型链
-
- 原型链:每一个对象都有原型,原型本身又是对象,所以原型又有原型,以此类推形成一个链式结构,称为原型链
- 对象在原型链中的访问规则:就近原则
-
- 当访问对象成员变量时,会先从自己的属性中查找,如果有就访问,没有就访问自己原型的,如果原型中没有,则访问原型的原型,以此类推,如果访问到原型链的顶端还是没有,则程序报错
xxxx is not undefined - 特殊情况:Object.prototype的原型对象是null
- 当访问对象成员变量时,会先从自己的属性中查找,如果有就访问,没有就访问自己原型的,如果原型中没有,则访问原型的原型,以此类推,如果访问到原型链的顶端还是没有,则程序报错
- d.函数本身也是对象
-
- 构造函数属于函数
- 5.instanceof运算符
-
- 语法:
对象 instanceof 构造函数 - 作用:检测构造函数的原型prototype在不在这个对象的原型链上
- 语法: