JS面向对象
面向对象相关概念
JS是一种基于对象的语言,和其它面向对象语言不同
对象
引用类型是一种数据结构,将数据和功能组织在一起,常被称为类
某个特定引用类型的实例
引用类型&对象--模具&实例
创建对象
基于Object的方式创建对象
从object类中通过New实例化出一个object对象
var 对象名称=new Object( );
var user = new Object();
给对象设置属性和方法
user.name = "张三";
user.pwd = "123456";
user.show=function(){document.write(this.name+"-"+this.pwd);}
user.show();
对象字面量
对象定义的一种简写形式
简化创建包含大量属性的对象的过程
在为函数传递大量可选参数时,可考虑使用对象字面量
var user = {
name : "张三",
pwd : "123456",
show:function(){
document.write(this.name+"-"+this.pwd+"
");
}
}
user.show();
练习1:创建person对象
基本Object对象的方式创建person对象
使用“.”为对象person添加属性name、age、job和address
添加方法show( ),在页面上显示对象属性name、age、job和address的值
工厂模式
软件工程领域的一种设计模式
抽象了创建对象的过程
通过函数封装创建对象的细节
function createUser(name,pwd){
var user = new Object();
user.name = name;
user.pwd = pwd;
user.show=function(){
document.write(this.name+"-"+this.pwd+"
");
}
return user;
}
var user1 = createUser("张三","123456");
var user2 = createUser("李四","654321");
user1.show();
user2.show();
工厂模式创建对象有何弊端
看不出类型--解决:构造函数
函数重复、浪费资源--解决:原型
构造函数
构造函数一般以大写字母开头
构造函数也是函数,只不过可以用来创建对象
与工厂模式对比
没有显式创建对象
直接将属性和方法赋给了this对象
没有return
function User(name,pwd){
this.name = name;
this.pwd = pwd;
this.show=function(){
document.write(this.name+"-"+this.pwd+"
");
}
}
var user1 = new User("张三","123456");
var user2 = new User("李四","654321");
user1.show();
user2.show();
原型prototype
每个函数都有一个prototype(原型)属性
是一个指针,指向一个对象
这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法
function User(name,pwd){
this.name = name;
this.pwd = pwd;
}
User.prototype.show=function(){
document.write(this.name+"-"+this.pwd+"
");
};
var user1 = new User("张三","123456");
var user2 = new User("李四","654321");
user1.show();
user2.show();
推荐使用 用混合方式构造对象
构造函数+prototype
构造函数里面设置属性
原型prototype中添加方法
练习1:原型方法去空格
// ☆ 在原型上写新的方法,方法名不要和原来的就有的方法名重合,不会会发生覆盖,即以下方法名trim0-4不能直接命名trim
字符串除了trim()方法,其他trim方法在ie上都不兼容,如:trim Start 、Left、 Right 、End()
使用原型方法以及正则表达式清除字符串空格,分别清除如下空格:
清除前面空格
清除后面空格
清除前后空格
清除所有空格
String.prototype.trim0=function()
{
reg=/^\s+/
return this.replace(reg,''); //去前面空格
}
String.prototype.trim1=function()
{
reg=/\s+$/
return this.replace(reg,''); //去后面空格
}
String.prototype.trim2=function()
{
reg=/^\s+|\s+$/g
return this.replace(reg,''); //去前后空格
}
String.prototype.trim3=function()
{
reg=/\s+/g
return this.replace(reg,''); //清除所有空格
}
var str=' kgc sss ';
console.log(str.trim0());
console.log(str.trim1());
console.log(str.trim2());
console.log(str.trim3());
练习2:原型方法排重
请将如下数组使用原型方法排重
var arr=[5,4,26,9,4,8,5,14];
Array.prototype.unique=function()
{
var temp=[];
for(var i=0;i<this.length;i++)
{
if(temp.indexOf(this[i])==-1)
{
temp.push(this[i]);
}
}
return temp
}
var arr=[5,4,26,9,4,8,5,14]
console.log(arr.unique());
JS面向对象高级
思考如下问题
function Person(){
this.foot = 2;
this.head=1;
}
“人类”对象的构造函数
function Man(name){
this.name=name;
}
“男人”对象的构造函数
问题:如何使“男人”继承“人”呢?
原型链继承-prototype属性
常见的方法
Man.prototype = new Person();
Man的prototype指向一个Person的实例,所有"男人"的实例,就能继承Person了
注意
如果替换了prototype对象:o.prototype = {};
要为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数:o.prototype.constructor = o;
function Person(){
this.foot = 2;
this.head=1;
}
function Man(name){
this.name=name;
}
Man.prototype = new Person();
Man.prototype.constructor = Man;
var man = new Man("张三");
原型链继承-直接继承prototype
对上一种方法的改进
由于Person对象中,不变的属性都可以直接写入Person.prototype。
所以,可以让Man()跳过 Person(),直接继承Person.prototype
经验
优点:效率比较高(不用执行和建立Person的实例了)
缺点:Man.prototype和Person.prototype现在指向了同一个对象,任何对Man.prototype的修改,都会反映到Person.prototype
父类
function Person(){}
把不变的属性卸载父类的原型身上
Person.prototype.foot = 2;
Person.prototype.head = 1;
子类
function Man(name){
this.name=name;
}
直接把父类的原型覆盖子类原型
Man.prototype = Person.prototype;
因为上一步已经把子类的构造属性覆盖了,所以我峨嵋你需要给子类的原型身上加上构造属性,并执行子类的构造函数
Man.prototype.constructor = Man;
var man1= new Man("张三");
利用空对象作为中介
空对象,几乎不占内存
修改Student的prototype对象,不会影响到Person的prototype对象
function Person(){}
Person.prototype.foot = 2;
Person.prototype.head = 1;
function Man(name){
this.name=name;
}
var F= function(){};
F.prototype = Person.prototype;
Man.prototype = new F();
var man1= new Man("张三");
Man.prototype.constructor = Man;
利用空对象作为中介-封装为函数
function Person(){}
Person.prototype.foot = 2;
Person.prototype.head = 1;
function Man(name){
this.name=name;
}
function extend(Child,Parent){
var F= function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}
extend(Man,Person);
var man1 = new Man("张三");
构造函数绑定
掌握构造函数绑定实现继承
call,是函数中的方法,所以必须有要函数来调用,第一个参数是需要改变this指向的对象,第二个参数是传递给方法的的实际参数,二u过还需要实际参数,就写一个逗号,继续传递实际函数,意思就是call的参数是一个一个传的;
apply
call和apply方法的异同:是函数中的方法,都是需要函数来调用,都是用来改变this指向的,不同点在于传参,call是一个一个传递的,apply需要使用数组来传参
bind bind 方法执行完返回的是一个函数,和call、apply区别在于其返回的是一个函数
function.call(thisObj[, arg1[, arg2[, [,...argN]]]])调用一个对象的一个方法,以另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法
function.apply(thisObj[, argArray])应用某一对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即A对象应用B对象的方法
两方法产生的作用相同,传参不同
function Person(address,sex){
this.foot = 2;
this.head = 1;
this.address = address;
this.sex = sex;
}
function Man(name){
//使用call或apply实现继承
//Person.call(this,"北京","女");
Person.apply(this,["北京","女"]);
this.name = name;
}
var man1 = new Man("张三");
作业1:
创建构造函数Person,添加属性姓名(name)、语文成绩(chinese)、数学成绩(math);添加三个方法,分别返回姓名、语文和数学成绩
创建构造函数Student,继承Person的属性和方法,并添加属于自己的属性身高(height),添加属于自己的方法,返回身高
创建Student的对象,并在页面上输出实例的姓名、语文、数学成绩和身高