面向对象的三大特征
1.封装: 把代码放入对象的方法中
2.继承: 一个对象拥有另一个对象 所有的成员 js高级的重点
3.多态: 一个对象在不同情况下的不同状态 js语言基本不涉及多态
代码演示 原型继承
// 父对象
let father = {
house: {
adderss: '房子',
price: 2000000,
},
car: {
drand: '车子'
price: 200000,
}
}
//子对象构造函数
function Sun(name, age) {
this.name = name
this.age = age
}
// 原型继承:把父对象 作为子对象构造函数的 原型
Sun.prototype = father
let p1 = new Sun('小李', 20)
let p2 = new Sun('小王', 20)
原型链 (重点面试题)
- 问 : 原型链的作用 答:继承
- 问 : js用什么技术实现面向对象继承的 答 : 原型链
| 原型链是什么? | 原型链 : 每一个对象都有自己的原型,而原型也是对象,也有自己的原型以此类推形成结构,称之为原型链 |
|---|---|
| 对象访问原型链规则 | 就近原则 :先访问自己的, 自己没有找原型,原型没有,就找原型的原型。 以此类推知道原型链的终点(null)如果还找不到。 属性获取undefined, 方法也会报错 XXX is not a function |
|---|---|
代码演示
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
instanceof 运算符 (面试题 了解)
面试会问 : instanceof的运算原理: 检测右边的构造函数在不在左边的实例对象的原型链中
1.instanceof:运算符(关键字) 检测 构造函数的原型在不在实例对象的原型链中
大白话: 有点类似于 亲子鉴定 鉴定构造函数和实例对象有没有血缘关系
2.语法 : 实例对象 instanceof 构造函数
3.应用 : 分装某些函数的时候,为了限制参数的数据类型, 可以用instanceof 做一个判断
演示应用场景
// 写一个翻转字符串
function reveseSter(str){
// 判断用户传的是不是str
if(str instanceof String){
// 1.把str切成数组
let arr = str.slice('')
// 2.数组翻转
arr.revese()
// 数组拼接字符串
console.log(arr.join(''))
}else{
console.log(str);
}
}
reveseSter('用户输入') //参数正确可以翻转
// 输入数字 参数错误 不能翻转 但是不会报错
原型链的应用代码演示
// 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="100%">
</div>
</div>
`
}
// 2.原型对象
Modal.prototype.show = function () {
// 创建空标签
let div = document.createElement('div')
// 设置标签内容
div.innerHTML = this.box
// 添加渲染页面
document.body.appendChild(div)
// 添加点击事件
div.querySelector('i').onclick = function () {
div.remove()
}
}
/* 点击按钮 */
//按钮1
document.querySelector('#btn1').onclick = function () {
// 3.实例对象
let p1 = new Modal('提示文本', './111.jpg')
p1.show()
}
//按钮2
document.querySelector('#btn2').onclick = function () {
// 3.实例对象
let p2 = new Modal('提示文本', './222.jpg')
p2.show()
}
//按钮3
document.querySelector('#btn3').onclick = function () {
// 3.实例对象
let p3 = new Modal('提示文本', './333.jpg')
p3.show()
}
</script>
函数补充(了解即可)
剩余参数
1. arguments关键字: 获取函数所有的 实参 arguments:是一个伪数组
2. 应用 : 用于参数 数量不确定的函数
例如: arr.push() Math.max()这些方法可以传很多个参数在函数内部就需要 arguments 来获取所有 的参数
变量的作用域 变量可以使用的范围
1.全局作用域:变量可以在页面任何地方使用
全局变量 :在大括号外边声明
2.局部作用域: 变量只能在函数内声明
局部变量 : 在函数内声明变量
3.块级作用域: 变量只能在大括号(分支+循环)内部使用
块级变量: 大括号内部声明变量
4.作用域链:
默认情况下,代码是全局作用域(0)级,声明函数之后会形成局部作用域(1级),函数内部有以 声明变量,又会形成局部作用域(2)级,以此类推形成作用域链
5.变量访问作用域链规则: 就近原则
for-in与for-of区别(面试必问)
1.功能不同
for-in :会遍历下标和属性
for-of :只会遍历元素
2.原型不同
for-in 会遍历原型中的属性
for-of :不会遍历原型中的属性
3.数据类型不同
for-in :能遍历数组和对象
for-of :只能遍历数组