面向对象
对象的组成:1.方法:过程,动态的;2.属性:状态,静态的
难点:this
/*
* 将对象的创建封装为一个函数
* 属性作为参数传递进去
* */
function CreatePerson(name) {
//1.原料
this.name = name;
//2.加工
this.showName = function () {
alert(this.name);
}
//3.出厂
//return obj;
//此处默认返回this
}
let p1 = new CreatePerson('Kangkang');
//new后面调用的函数叫做构造函数
p1.showName();
let p2 = new CreatePerson('Michael');
p2.showName();
//当new调用一个函数时,函数中的this就是new创建的对象,而且函数的返回值直接就是this
//被称为隐式返回
对象的引用&原型
在上例中若判断p1.showNam===p2.showName,它们都是指的方法showName本身,但是却返回false。因为两者引用地址不同。每个对象的方法有自己的内存地址。
基本类型:赋值是值的复制
对象类型:赋值不仅是值的赋值,也是引用的传递
原型:去改写对象下面公用的方法或者属性,让公用的方法或者属性在内存中只存在一份。提高性能。
可类比于CSS
原型:CSS中的class
普通方法:CSS中的style
//普通函数写法
let arr = [1,2,3,4,5];
arr.sum1 = function () {
let result = 0;
for(let i=0;i<this.length;i++){
result += this[i];
}
return result;
}
/*
* 原型:prototype,要写在构造函数下面
*/
let arr1 = [1,2,3];
let arr2 = [1,2];
Array.prototype.sum2 = function () {
let result = 0;
for(let i=0;i<this.length;i++){
result += this[i];
}
return result;
}
alert(arr1.sum2());
alert(arr2.sum2());
//普通函数的优先级高于原型
将上面的creatPerson改为原型写法
function CreatPerson2(name) {
this.name = name;
}
CreatPerson2.prototype.showName2 = function () {
alert(this.name);
}
/*
* 面向对象写法:
* function 构造函数(){
* this.属性;
* }
*
* 构造函数.原型.方法 = function(){};
*
* let 对象1 = new 构造函数();
* 对象1.方法();
* */
改为面向对象写法时要注意的this问题
oDiv. = function () {
this: oDiv
}
oDiv. = show;
function show() {
this: oDiv //this依然是oDiv
}
oDiv. = function () {
show();
} //this在function show中,
function show() { //而show是在function中被调用,this指向window
this: window
}
选项卡的实现
非面向对象代码写法
let oParent = document.getElementById('div1');
let aInput = oParent.getElementsByTagName('input');
let aDiv = oParent.getElementsByTagName('div');
for(let i=0;i<aInput.length;i++){
aInput[i].index = i;
aInput[i]. = function () {
for(let i=0; i<aInput.length;i++){
aInput[i].className = '';
aDiv[i].style.display = 'none';
}
this.className = 'active';
aDiv[this.index].style.display = 'block';
}
}
修改为面向对象思路
//尽量不要出现函数嵌套函数
//可以有全局变量
//把中不是赋值的语句放到单独函数中
将代码初步修改后出现this的指向问题,分析及代码如下
/*
* 全局变量就是属性
* 函数就是方法
* Onload中创建对象
* 改this指向问题:事件或者定时器,尽量让面向对象中的this指向对象
* */
window. = function () {
let t1 = new Tab();
t1.create();
}
function Tab(id) {
//此处的传参id增加复用性
//这里面的this是在构造函数里面
// new一个构造函数时调用,this指向创建出来的对象
this.oParent = document.getElementById(id);
this.aInput = this.oParent.getElementsByTagName('input');
this.aDiv = this.oParent.getElementsByTagName('div');
}
Tab.prototype.init = function () {
//t1.init()调用,this指向t1
for(let i=0;i<this.aInput.length;i++){
this.aInput[i].index = i;
this.aInput[i]. = this.change;
}
}
Tab.prototype.change = function () {
//在this.aInput[i]. = this.change调用
// this指向点击的按钮,即上文中的this.aInput[i]
//应将this调整为对象t1
//xxx处依然应当为按钮
for(let i=0; i<this.aInput.length;i++){
this.aInput[i].className = '';
this.aDiv[i].style.display = 'none';
}
xxx.className = 'active';
this.aDiv[xxx.index].style.display = 'block';
}
调整方法的调用方式,即可改变this的指向
Tab.prototype.create = function () {
for(let i=0;i<this.aInput.length;i++){
const This = this;//保存当前作为对象的this,通过赋值方式传递给change
this.aInput[i].index = i;
this.aInput[i]. = function () {
This.change(this);//修改了此处的调用方式,让change的this指向对象
}
}
}
Tab.prototype.change = function (obj) {
//将按钮作为参数传递进来
for(let i=0; i<this.aInput.length;i++){
this.aInput[i].className = '';
this.aDiv[i].style.display = 'none';
}
obj.className = 'active';
this.aDiv[obj.index].style.display = 'block';
}