原型 prototype
def:每一个函数天生自带一个属性,为prototype,是一个对象
构造函数也是函数,也会有这个自带的空间prototype
可以使用对象操作方法,向prototype对象里面添加内容
每个对象天生自带一个属性proto,指向所属构造函数的prototype
// eg:p1.proto === Person.prototype
当你访问对象的成员时,首先在自己身上查找,如果没有,自动去proto上查找
对象
- 定义:每一个对象,在你访问他的成员的时候,如果自己没有这个属性
=> 会自动去所屈构造两数的 prototype 上查找 - 自定义构造两数创建的对象也是对象, 当你访问某一个成员的时候
=> 如果没有,也会自动去所属构造函数的原型上查找
=> 哪一个构造函数创建的对象,这个对象就属于哪一个构造函数
=> 因为构造函数在创建对象的过程,我们起名为 实例化 的过程
-> 创建出来的对象叫做这个构造函数的一个 实例化对象
function Person() {}
Person.prototype.sayHi = function () { console.log('hi'); }
console.log(Person.prototype);
//创建一个实例化对象
//p1是Person实例化出来的对象,p1就是属于Person这个构造函数的
//当你访问p1的sayHi成员时,p1自己是没有的,会自动去Person的 原型 上找
var p1 = new Person();
console.log(p1);
p1.sayHi();
//创建第二个实例化对象
var p2 = new Person();
console.log(p2);
p2.sayHi();
/*
p1的sayHi和p2的sayHi都是使用的Person构造函数上的方法
只用向Person的原型上添加一些方法,所有Person的每一个实例都可以使用
而且使用的都是同一个函数 不存在浪费空间的问题
*/
案例 - 面向对象-选项卡
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>java script</title>
<style>
* {
margin: 0;
padding: 0;
}
ul , ol , li {
list-style: none;
}
.tab {
width: 600px;
height: 400px;
border: 10px solid #333;
margin: 50px auto;
display: flex;
flex-direction: column;
}
ul {
height: 60px;
display: flex;
}
ul > li {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-size: 40px;
color: black;
background-color: skyblue;
cursor: pointer;
}
ul > li.active{
background-color: orange;
}
ol {
flex: 1;
position: relative;
}
ol > li {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
font-size: 100px;
color: white;
background-color: purple;
display: none;
justify-content: center;
align-items: center;
}
ol > li.active {
display: flex;
}
</style>
</head>
<body>
<div class="tab" id="box">
<ul>
<li class="active">1</li>
<li>2</li>
<li>3</li>
</ul>
<ol>
<li class="active">1</li>
<li>2</li>
<li>3</li>
</ol>
</div>
<script>
/*
1. 抽象内容
+ 一个能够完成选项卡的对象,需要有哪些属性和方法
+ 属性:所有可点击的按钮盒子
+ 属性:所有可以切换的选项盒子
+ 方法:能添加点击事件的方法
2. 书写构造函数
+ 能创建一个对象,包含两个属性一个方法
+ 属性直接写在构造函数体内
+ 方法写在构造函数的原型上
*/
// 2. 书写构造函数
function Tabs(ele) {
// 范围
this.ele = document.querySelector(ele);
// 在范围内找到所有可点击的盒子
this.btns = this.ele.querySelectorAll(' ul > li');
// 在范围内找到所有需要切换显示的盒子
this.tabs = this.ele.querySelectorAll(' ol > li');
}
// 原型上书写方法
Tabs.prototype.change = function () {
// 给所有btns里面的按钮添加点击事件
// 不能直接使用t这个变量 因为后期可能有修改
//console.log(this.btns);// 原本是 t.btns
// 提前保存一下this
var _this = this;
for( var i = 0 ; i < this.btns.length ; i ++ ){
// 提前保存索引
this.btns[i].setAttribute('index',i);
this.btns[i].addEventListener('click',function () {
console.log('clicked')
// 需要让实例的btns/tabs里面的每一个没有active类名
// 这里不是在change函数的作用域了,而是事件处理函数的作用域
// 在事件处理函数中,this指向当前事件的事件源
console.log(this);
// 当你访问 _this时,其实是在访问变量
// 自己作用域没有.就回去上一级作用于查找
for ( var j = 0 ; j < _this.btns.length ; j ++ ){
_this.btns[j].className = '';
_this.tabs[j].className = '';
}
// 当前点击的li有active的类名
this.className = 'active';
// 让实例身上的tabs里面索引对应的哪一个li有active类名
var index = this.getAttribute('index') - 0;
_this.tabs[index].className = 'active';
})
}
}
// 使用的时候 选项卡就可以使用了
var t = new Tabs('#box')
// 实例对象在调用方法,函数调用方式:对象.函数名(),函数内部的this指向 点 前面的 xxx
//chang函数里面的this就是t
t.change();
console.log(t);
</script>
</body>
</html>
/*
问题1 实例对象身上__proto__指向谁?
=> 指向所属构造函数的prototype
=> p1所属的构造函数时Person
=> p1.__proto__指向Person.prototype
问题2 Person.prototype的__proto__指向谁?
=> Person.prototype所属的构造函数是谁
=> 因为Person.prototype是一个对象数据类型(Object)
=> 在JS内所有的Object数据类型都是属于Object这个内置构造函数
=> Person.prototype是属于Object这个内置构造函数的
=> Person.prototype的__proto__指向Object.prototype
问题3 Person的__proto__指向谁?
=> Person是一个函数,函数本身也是一个对象,就会有__proto__
=> 在js内 所有函数都是属于内置构造函数 Function 的实例
=> Person.__proto__指向Function.prototype
问题4 Object.prototype的__proto__指向谁?
=> Object.prototype是一个对象数据类型,只要是对象,都是数据Object这个内置构造函数的
=> Object.prototype的__proto__指向null
=> 注意:Object.prototype在JS内叫做顶级原型,不再有__proto__了
问题5 Object的__proto__指向谁?
=> Object是一个内置构造函数,同时也是一个函数,同时也是一个对象
=> 在JS内,所有函数都是内置构造函数Function的实例
=> Object.__proto__指向Function.prototype
问题6 Function.prototype指向谁?
=> Function.prototype也是个对象数据类型
=> 只要是对象数据类型都是Object的实例
=> Function.prototype 的 __proto__ 指向Object.prototype
问题7 Function的__proto__指向谁?
=> Function也是一个内置构造函数,也是一个函数
=> 在JS内,所有的函数都是属于内置构造函数Function的实例
=> Function自己是自己的构造函数
=> Function自己是自己的实例对象
=> Function所属的构造函数是Function
*/
image.png
原型链
- 用proto串连起来的对象链状结构
- 每个对象数据类型都有一个属于自己的原型链
- 作用:对象访问机制
对象访问机制:
- 当你需要访问对象成员的时候
- 首先在自己身上查找,如果有直接用
- 如果没有,就自动去proto上查找,直到Object.prototype都没有,就返回undefined
网友评论