面向对象特征
面向对象三大特征
封装 继承 多态
封装
继承
多态
原型继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
/*
1.继承 : 一个对象 拥有 另一个对象 所有的 成员
2.原型继承 :把父对象 作为子对象构造函数的原型
*/
// 父对象
let father={
house:{
address:'汤臣一品',
price:20000000
},
car:{
brand:'劳斯莱斯幻影',
price:15555
}
}
// 构造函数
function Son(name,age){
this.name=name
this.age=age
}
// 原型继承,把父对象作为子对象构造函数的原型
Son.prototype=father
// 实例对象
let s1=new Son('张三',18)
let s2=new Son('李四',20)
console.log(s1,s2);
//可选 : 原型继承之后,由于父对象覆盖原来的 子对象构造函数原型, 就会导致constructor消失.
//解决办法: 手动添加。(对开发几乎没有影响,也可以不加)
</script>
</body>
</html>
原型链
01 原型链
<script>
/*
1.原型链 : 每一个对象都有自己的原型, 而原型也是对象,也会有自己的原型,此次类推形成链式结构。称之为原型链。(原型链的终点是null)
2.对象访问原型链规则 : 就近原则
* 对象先访问自己的,自己没有就找原型的,原型没有就找原型的原型,一直到原型链终点null.如果还找不到。 属性则获取undefined, 方法则会报错 xxx is not function
*/
// 构造函数
function Person(name,age){
this.name=name
this.age=age
}
// 原型对象
Person.prototype.eat=function(){
console.log('吃东西');
}
Person.prototype.type='哺乳动物'
// 实例对象
let p1=new Person('张三',18)
// 查看p1的原型对象
console.log(p1.__porto_.constructor); //Person
console.log(p1.__porto_===Person.prototype);
// 查看p1的原型对象的原型
console.log(p1.__porto_.__porto_.constructor);//Object
console.log(p1.__porto_.__porto_===Object.prototype); //true
</script>
02 内置对象原型链
内置对象原型链
<script>
/*
1.原型链 : 每一个对象都有自己的原型, 而原型也是对象,也会有自己的原型,此次类推形成链式结构。称之为原型链。(原型链的终点是null)
2.对象访问原型链规则 : 就近原则
3.原型链作用 继承
js用什么技术实现面向对象的继承 :原型链*/
// 数组对象
//实例化对象
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
</script>
03-instanceof运算符
<script>
/*
1. instanceof(关键字): 运算符。 用于检测 构造函数的prototype在不在实例对象的原型链中
说人话: 亲子鉴定,鉴定两个对象之间有没有血缘关系
面试点 检测右边构造函数的原型在不在左边实例对象原型链中
2. 实例对象 instanceof 构造函数
检测 右边构造函数的prototype 在不在 左边实例对象的原型链中
3. 应用 : 封装某些函数的时候,为了限制参数的类型,可以用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 reverseStr(arr){
//
if(arr instanceof Array){
arr.reverse()
console.log(arr.join(''));
}else{
console.log('数据类型');
}
}
reverseStr('你','是')
//封装一个函数,要求这个函数必须要传数组类型、 传其他类型不可以
function fn(arr){
if( arr instanceof Array){
console.log( arr.reverse() )
}else{
console.log('数据类型错误')
}
}
fn( [10,20,30] )
fn( 'abc' )
</script>
03原型链应用-封装提示框
<!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>面向对象封装消息提示</title>
<style>
.modal {
width: 300px;
min-height: 100px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
border-radius: 4px;
position: fixed;
z-index: 999;
left: 50%;
top: 50%;
transform: translate3d(-50%, -50%, 0);
background-color: #fff;
}
.modal .header {
line-height: 40px;
padding: 0 10px;
position: relative;
font-size: 20px;
}
.modal .header i {
font-style: normal;
color: #999;
position: absolute;
right: 15px;
top: -2px;
cursor: pointer;
}
.modal .body {
text-align: center;
padding: 10px;
}
.modal .footer {
display: flex;
justify-content: flex-end;
padding: 10px;
}
.modal .footer a {
padding: 3px 8px;
background: #ccc;
text-decoration: none;
color: #fff;
border-radius: 2px;
margin-right: 10px;
font-size: 14px;
}
.modal .footer a.submit {
background-color: #369;
}
</style>
</head>
<body>
<button id="btn1">消息提示1</button>
<button id="btn2">消息提示2</button>
<button id="btn3">消息提示3</button>
<!-- <div class="modal">
<div class="header">提示消息 <i>x</i></div>
<div class="footer">
<img src="./111.jpg" alt="" width="80%">
</div>
</div> -->
<script>
// 1.构造函数 里面的每一个模态框不同的数据
function Modal(title,url){
this.title=title
this.url=url
this.box=`
<div class="modal">
<div class="header">${this.title} <i>x</i></div>
<div class="footer">
<img src="${this.url}" alt="" width="80%">
</div>
</div>
`
}
// 原型 灭一个模态框共有的方法
Modal.prototype.show=function(){
// (1)创建空标签
let div=document.createElement('div')
// (2)设置标签内容
div.innerHTML=this.box
// 谁调用这个函数,this就指向谁
// (3)添加到页面
document.body.appendChild(div)
div.querySelector('i').onclick=function(){
div.remove()
}
}
/* 点击按钮 */
//按钮1
document.querySelector('#btn1').onclick = function(){
// 实例对象
let m1=new Modal('提示文字','./111.jpg')
m1.show()
}
//按钮2
document.querySelector('#btn2').onclick = function(){
let m2=new Modal('提示文字','./222.jpg')
m2.show()
}
//按钮3
document.querySelector('#btn3').onclick = function(){
let m3=new Modal('友情提示','./333.jpg')
m3.show()
}
</script>
</body>
</html>
04函数补充
01-arguments关键字
<script>
/*
1. arguments关键字: 获取函数所有的 实参
是一个伪数组 : 有数组三要素(元素、下标、长度),但是不能使用数组的方法
2. 应用 : 一般用于参数数量不限的函数.
例如: arr.push() Math.max() 这些方法可以传很多个参数,在函数内部就需要arguments来获取所有的实参
*/
function fn(a, b) {
console.log(a); //undefined
console.log(b); //undefined
console.log(a + b); //NaN
console.log(arguments);
}
fn();
fn(10);
fn(10, 20);
fn(10, 20, 30);
fn(10, 20, 30, 40);
</script>
02-剩余参数rest
<script>
/*
1. arguments关键字: 获取函数所有的 实参
是一个伪数组 : 有数组三要素(元素、下标、长度),但是不能使用数组的方法
2. 应用 : 一般用户参数数量不限的函数.
例如: arr.push() Math.max() 这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参
3. 剩余参数(rest参数) : 获取函数剩余的所有实参
语法: function 函数名(形参1,...形参2){}
特点: (1)只能作为最后一个参数 (2)是真数组
4. 剩余参数,rest参数可以替代arguments
*/
function fn(...b){
console.log(b)//10
console.log(arguments)
}
fn(10)
fn(10,20)
fn(10,20,30)
fn(10,20,30,40)
</script>
03函数默认参数
<script>
/*
1. arguments关键字: 获取函数所有的 实参
是一个伪数组 : 有数组三要素(元素、下标、长度),但是不能使用数组的方法
2. 应用 : 一般用户参数数量不限的函数.
例如: arr.push() Math.max() 这些函数实参数量不限,底层原理就是使用arguments来接收所有的实参
3. 剩余参数(rest参数) : 获取函数剩余的所有实参
语法: function 函数名(形参1,...形参2){}
特点: (1)只能作为最后一个参数 (2)是真数组
4. 一般情况下,rest参数可以替代arguments
5. 函数默认参数
function 函数名(形参=默认值){ }
*/
function fn(a=0,b=0){
//fn(a,b) 10+undefined=NUN
//以前: 逻辑或短路
// 找真 : 左边是真就返回左边式子的值,否则返回右边式子的值
// a = a || 1
// b = b || 2
console.log( a + b )
}
fn(10)
fn(5,0)
</script>
04js变量作用域
<script>
/*
1 变量作用域:变量可以使用的范围
2.三种作用域
全局作用域:变量可以在页面任何地方使用
全局变量:在大括号外面声明
局部作用域:变量只能在函数内部
局部变量:在函数内声明的变量
块级作用域:变量只能在大括号(分支+循环)内部使用
块级变量:在大括号内部声明的变量 */
function f1(){
let num=5
}
function f2(){
let num=5
}
</script>
05作用域链
<script>
/* 1 变量作用域:变量可以使用的范围
2.三种作用域
全局作用域:变量可以在页面任何地方使用
全局变量:在大括号外面声明
局部作用域:变量只能在函数内部
局部变量:在函数内声明的变量
块级作用域:变量只能在大括号(分支+循环)内部使用
块级变量:在大括号内部声明的变量
3.作用域链
默认情况下 代码是全局作用域(0级),声明函数之后就会变成局部作用域(1级),函数内部又可以声明函数,有会形成局部作用域(2级),以此类推
4.变量访问作用域链规则:就近原则
先在当前作用域找声明,有声明就用自己的,自己没有就找上级声明,有酒访问,没有就继续找上级找到最顶级(0级)还是未找到就 报错 xxx is not defined
*/
// 0级
let num=10
function fn(){
// 1级
// let num =20
console.log(num);//10
function fn1(){
// 2级
let num =30
// console.log(num);//30
}
fn1()
}
fn()
// console.log(num);//10
</script>
06let 与const 的区别
07 for in与 for of 的区别
y>
<script>
/* for-in与for-of区别
1.功能不同
for-in是遍历数组的下标和元素
for-of是遍历数组的元素
2.原型的属性
for-in会遍历原型的属性
for-of不会遍历原型的属性
3.数据类型不同
for-in会遍历数组和对象
for-of只能遍历数组
总结:如果想要遍历数组的下标和元素就用for in,如果想遍历数组的元素就用for of
*/
//数组
let arr = ['a','b','c']//下标0 1 2
//给原型添加成员
Array.prototype.age = 30
//对象
let obj = {name:'ikun',age:30}
//遍历数组
//for-in
for(let key in arr){
console.log(key,arr[key])//下标,元素
}
//for-of
for (let item of arr ) {
console.log(item) //元素
}
//遍历对象 : 程序报错
// for (let item of obj ) {
// console.log(item) //属性名
// }
</script>