JS基本篇--面向对象与原型

建立对象

var box = new Object();//建立对象
box.name = 'Lee';      //增加属性
box.age = 100;
box.run = function(){
    return this.name + this.age + "运转中";  //this 示意当前作用域下对象
}

// this 示意new Object()实例出来的谁人对象
alert(box.run());

这就是建立对象最基础的要领,然则有个瑕玷,想建立一个相似的对象,就会发生大批的代码。

工场形式

为了处理多个相似对象声明的题目,我们能够运用一种叫做工场形式的要领,这类要领就是为了处理实例化对象发生大批反复的题目。

function createObject(name,age){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.run = function(){
        return this.name+this.age+"岁岁数";
    }
    return obj;
}

var box1 = createObject('Lee',20);
var box2 = createObject('Jack',30);
console.log(box1.run());
console.log(box2.run());

工场形式处理了反复实例化的题目,但另有一个题目,那就是辨认题目,由于基础没法搞清他们究竟是哪一个对象的实例。

alert(typeof box1); //Object
alert(box1 instanceof Object);//true

组织函数

ECAMScript中采纳组织函数(组织要领)可用来建立特定的对象。相似于Object对象。

//组织函数
function Box(name,age){
    this.name = name;
    this.age = age;
    this.run = function(){
        return this.name + this.age +"运转中...";
    };
};

var box1 = new Box('Lee',100);
var box2 = new Box('Jack',200);

console.log(box1.run());
console.log(box2.run());

运用组织函数的要领,即处理了反复实例化的题目,又处理了对象辨认的题目,但题目是,这里并没有new Object(),为何能够实例化Box(),这个是哪里来的呢?

运用了组织函数的要领,和运用工场形式的要领他们差别之处以下:
1.组织函数要领没有显现的建立对象(new Objectt()),但它在背景自动var obj = new Object();
2.直接将属性和要领赋值给this对象,this就相称于obj;
3.没有return语句,不需要返回对象援用,它是在背景自动返回的。

//组织函数
function Box(name,age){
    this.name = name;
    this.age = age;
    this.run = function(){
        return this.name + this.age +"运转中...";
    };
};

function Dack(name,age){
    this.name = name;
    this.age = age;
    this.run = function(){
        return this.name + this.age +"运转中...";
    };
};

var box1 = new Box('Lee',100);
var box2 = new Box('Jack',200);
var box3 = new Dack('MrLee',300);

console.log(box1.run());
console.log(box2.run());
console.log(box3.run());

//处理了对象辨认题目
console.log(box1 instanceof Box); //true
console.log(box2 instanceof Box); //true
console.log(box3 instanceof Box); //false
console.log(box3 instanceof Dack);//true

对象假装:运用call()要领

var o= new Object();
Box.call(o,'Lee',100);
console.log(o.run());

看下一个题目:

 var box1 = new Box('Lee',100); //实例化后地点为1
 var box2 = new Box('Lee',100); //实例化后地点为2

 console.log(box1.name == box2.name); //true
 console.log(box1.age == box2.age);      //true
 console.log(box1.run() == box2.run());//true //组织函数体内的要领的值是相称的
 console.log(box1.run == box2.run); //false //由于他们比较的是援用地点
 

上面的代码运转申明援用地点不一样,那末组织函数内的要领也能够如许写:

this.run = new Function("return this.name + this.age +'运转  

怎样让他们的援用地点一样,下面代码:

function Box(name,age){
    this.name = name;
    this.age = age;
    this.run = run;
};

function run(){
    return this.name +this.age+"运转中...";
}
 var box1 = new Box('Lee',100); //实例化后地点为1
 var box2 = new Box('Lee',100); //实例化后地点为2
 console.log(box1.run == box2.run); //true //由于他们比较的是援用地点  
 

把组织函数内部的要领经由历程全局来完成援用地点一致。
虽然运用了全局函数run()来处理了保证援用地点一致的题目,然则这类体式格局又带来了一个新的题目,全局中的this在对象挪用的时刻是Box自身,而当一般函数挪用的时刻,this又代表window。

原型

function Box(){
       //组织函数函数体内什么都没有,这里如有过,叫做实例属性,实例要领
} 

Box.prototype.name="Lee"; //原型属性
Box.prototype.age=100;
Box.prototype.run=function(){ //原型要领
    return this.name+this.age+"运转中...";
}

var box1=new Box();
var box2=new Box();
console.log(box1.run == box2.run); //true
console.log(box1.prototype);//这个属性是一个对象,接见不到
console.log(box1.__proto__);//这个属性是一个指针指向prototype原型对象。 

假如是实例要领,差别的实例化,他们的要领地点是不一样的,是唯一的。
假如是原型要领,那末他们的地点是同享的,人人都一样。

console.log(box1.constructor); //组织属性,能够猎取组织函数  

PS:IE浏览器在剧本接见__proto__会不能辨认,火狐和谷歌及其他某些浏览器能辨认。虽然能够输出,然则没法猎取内部信息。

推断一个对象是不是指向该组织函数的原型对象,能够运用isPrototypeOf()要领来测试。

console.log(Box.prototype.isPrototypeOf(box1)); //true //只需实例化对象,即都邑指向

原型形式的实行流程:
1.先查找组织函数实例里的属性或要领,假如有,马上返回;
2.假如组织函数实例里没有,则去它的原型对象里找,假如有,就返回。

怎样推断属性时组织函数的实例里,照样原型里?能够运用hasOwnProperty()函数来考证:

console.log(box1.hasOwnProperty('name'));//假如实例里有返回true,不然返回false  

怎样推断属性是原型里的?

function Box(){
       
} 

Box.prototype.name="Lee"; //原型属性
Box.prototype.age=100;
Box.prototype.run=function(){ //原型要领
    return this.name+this.age+"运转中...";
}

function isProperty(object,property){
    return !object.hasOwnProperty(property) && (property in object);
}
var box1=new Box();
console.log(isProperty(box1,'name'));

为了让属性和要领更好的表现封装的结果,而且削减不必要的输入,原型的建立能够运用字面量的体式格局

运用字面量的体式格局建立原型对象,这里的{}就是对象,是object,new Object就相称于{}

function Box(){} 

Box.prototype={
    name:'Lee',
    age:100,
    run:function(){
        return this.name+this.age+"运转中...";
    }
}

var box = new Box();
console.log(box.constructor == Box); //false 

字面量建立的体式格局运用constructor属性不会指向实例,而会指向Object,组织函数建立的体式格局则相反。
这里的Box.prototype={}就相称于建立了一个新的对象,所以 box.constructor是Object。
怎样让box.constructor指向Box呢?

function Box(){} 

Box.prototype={
    constructor:Box,//直接强迫指向即可
    name:'Lee',
    age:100,
    run:function(){
        return this.name+this.age+"运转中...";
    }
}

var box = new Box();
console.log(box.constructor == Box); //true

重写原型,不会保存之前原型的任何信息,把本来的原型对象和组织函数对象的实例切断了。

function Box(){} 

Box.prototype={
    constructor:Box,
    name:'Lee',
    age:100,
    run:function(){
        return this.name+this.age+"运转中...";
    }
}

//重写原型
Box.prototype={
    age:200
}
var box = new Box();
console.log(box.name); //undefined

检察sort是不是是Array原型对象里的要领
alert(Array.prototype.sort);

在以下 推断String原型对象里是不是有substring要领
alert(String.prototype.substring);

给String 增加addstring要领:

String.prototype.addstring=function(){
    return this+',被增加了!';
}
var box="Lee";
console.log(box.addstring());

注:原型形式建立对象也有本身的瑕玷,它省略了组织函数传参初始化这一历程,带来的瑕玷就是初始化的值都是一致的。而原型最大的瑕玷就是它最大的长处,那就是同享。

原型中所有属性是被许多实例同享的,同享关于函数异常适宜,关于包括基础值的属性也还能够。但假如属性包括援用范例,就存在肯定的题目:

function Box(){}

Box.prototype={
    constructor:Box,
    name:'Lee',
    age:100,
    family:['哥哥','姐姐','mm'],
    run:function(){
        return this.name+this.age+"运转中...";
    }
};

var box1 = new Box();
console.log(box1.family); //'哥哥','姐姐','mm'
box1.family.push("弟弟");
console.log(box1.family);//'哥哥','姐姐','mm','弟弟'

var box2 = new Box();
console.log(box2.family);//'哥哥','姐姐','mm','弟弟'

从上面代码能够看出,在第一个实例修改后援用范例,坚持了同享。box2.family同享了box1增加后的援用范例的原型。

为了处理组织传参和同享题目,能够组合组织函数+原型形式:

function Box(name,age){  //坚持自力的用组织函数
    this.name=name;
    this.age=age;
    this.family=['哥哥','姐姐','mm'];
}

Box.prototype={ //坚持同享的用原型
    constructor:Box,
    run:function(){
        return this.name+this.age+"运转中...";
    }
}

var box1 = new Box('Lee',100);
console.log(box1.family); //'哥哥','姐姐','mm'
box1.family.push("弟弟");
console.log(box1.family);//'哥哥','姐姐','mm','弟弟'



var box2 = new Box('Jack',200);
console.log(box2.family); //'哥哥','姐姐','mm' //援用范例没有运用原型,所以没有同享

动态原型形式

//把原型封装到组织函数里
function Box(name,age){
    this.name=name;
    this.age=age;
    this.family=['哥哥','姐姐','mm'];

    console.log('原型初始化最先');  //实行了两次
    Box.prototype.run=function(){
        return this.name+this.age+"运转中...";
    }
    console.log('原型初始化完毕'); //实行了两次
}

//原型的初始化,只需第一次初始化就能够了,没必要每次组织函数实例化的时刻都初始化
var box1 = new Box('Lee',100);
var box2 = new Box('Jack',200);

为了只让第一次初始化,那末就推断

function Box(name,age){
    this.name=name;
    this.age=age;
    this.family=['哥哥','姐姐','mm'];

    if(typeof this.run!='function'){
        console.log('原型初始化最先'); //实行了一次次
        Box.prototype.run=function(){
            return this.name+this.age+"运转中...";
        };
        console.log('原型初始化完毕'); //实行了一次
    }
}

//原型的初始化,只需第一次初始化就能够了,没必要每次组织函数实例化的时刻都初始化
var box1 = new Box('Lee',100);
var box2 = new Box('Jack',200);

寄生组织函数
假如以上都不能满足需要,能够运用一下寄生组织函数。
寄生组织函数=工场形式+组织函数

function Box(name,age){
    var obj = new Object();
    obj.name=name;
    obj.age=age;
    obj.run=function(){
        return this.name+this.age+"运转中...";
    }
    return obj;
}

var box1 = new Box('Lee',100);
var box2 = new Box('Jack',200);

稳妥组织函数

在一些平安的环境中,比方制止运用this和new,这里的this是组织函数里不运用的this,这里的new是在外部实例化组织函数时不运用new。这类建立体式格局叫做稳妥组织函数。

function Box(name,age){
    var obj = new Object();
    obj.name=name;
    obj.age=age;
    obj.run=function(){
        return this.name+this.age+"运转中...";
    }
    return obj;
}

var box1 = Box('Lee',100);
var box2 = Box('Jack',200);

继续

继续是面向对象中一个比较中心的观点。别的正统面向对象言语都邑用两种体式格局完成继续:一个是接口完成,一个是继续。而ECMAScript只支撑继续,不支撑接口完成,而完成继续的体式格局依托原型链完成。

function Box(){
    this.name="Lee";
}

function Jack(){
    this.age=100;
}

Jack.prototype = new Box();

var jack = new Jack();
console.log(jack.name); //Lee

为了处理援用同享和超范例没法传参的题目,我们采纳一种叫借用组织函数的手艺,或许成为对象假装(捏造对象、典范继续)的手艺处理这两个题目。

function Box(name){
    this.name=name;
}

Box.prototype.age=200;

function Jack(name){
    Box.call(this,name);
}

var jack = new Jack('Lee');

console.log(jack.name);//Lee
console.log(jack.age);//undefined   

然则上面的代码能够看出,对象假装没有继续原型链上的age属性。所以要继续Box的原型,就出现下面的组合继续。
组合继续等于原型链+借用组织函数的形式

function Box(name){
    this.name=name;
}

Box.prototype.age=200;

function Jack(name){
    Box.call(this,name);
}

Jack.prototype = new Box();

var jack = new Jack('Lee');

console.log(jack.name);//Lee
console.log(jack.age);//200

原型式继续

//暂时中转函数
function obj(o){
    function F(){};
    F.prototype = o;
    return new F();
}

//这是字面量的声明体式格局,相称于var box = new Box();
var box={
    name:'Lee',
    age:100,
    family:['哥哥','姐姐','mm']
};

var box1 = obj(box);
console.log(box1.family);//'哥哥','姐姐','mm'
box1.family.push('弟弟');
console.log(box1.family);//'哥哥','姐姐','mm','弟弟'

var box2 = obj(box);
console.log(box2.family);//'哥哥','姐姐','mm','弟弟'

存在的题目就是援用范例同享了。

寄生式继续
把原型式与工场形式结合起来。

//暂时中转函数
function obj(o){
    function F(){};
    F.prototype = o;
    return new F();
}


//寄生函数
function create(o){
    var f=obj(o);
    f.run=function(){
        return this.name+"要领";
    }
    return f;
}


//这是字面量的声明体式格局,相称于var box = new Box();
var box={
    name:'Lee',
    age:100,
    family:['哥哥','姐姐','mm']
};

var box1 = create(box);
console.log(box1.run());

寄生组合继续

//暂时中转函数
function obj(o){
    function F(){};
    F.prototype = o;
    return new F();
}


//寄生函数
function create(box,desk){
    var f=obj(box.prototype);
    f.constructor=desk; //调解原型组织指针
    desk.prototype=f;
}


function Box(name,age){
    this.name=name;
    this.age=age;
}

Box.prototype.run=function(){
    return this.name+this.age+"运转中...";
}

function Desk(name,age){
    Box.call(this,name,age); //对象假装
}

//经由历程寄生组合继续来完成继续
create(Box,Desk); //这句话用来替换Desk.prototype = new Box();

var desk = new Desk('Lee',100);
console.log(desk.run());
    原文作者:风雨后见彩虹
    原文地址: https://segmentfault.com/a/1190000004580861
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞