js面向对象基本

js面向对象基础

javascriptnew xxx的时刻发生了什么?

人人在一样平常的js开辟中,会经常见到类似于下面的代码块:

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.sayName = function(){
    console.log('this cat name is:'+this.name);
}
Cat.prototype.sayAge = function(){
    console.log('this cat age is:'+this.age);
}

var cat = new Cat('大黄','黄色');

到这边的话,我们就胜利建立了一个Cat类的对象cat。(注意下,虽然这边我们依然谈类,然则因为JS是一门鸭子范例的言语,只需具有某个类肯定的特征,比方某些要领、属性,那末我们就以为这个对象就是这个类的)
那末在cat对象的建立历程当中,又发生了那些事情呢?建立一个对象,平常会阅历以下几个步骤:

  • 建立一个空对象o

  • o的原型指向函数的原型

  • 在新建立的对象o上实行函数,即function.apply(o,arguments)

  • 返回对象o

经由以上四个步骤我们就能够创实例化一个Cat范例的对象。

这里说个人人比较轻易失足的处所,就是function优惠返回值的状况。比方:

function F(name){
    this.name = name;
    return "F";
}

这边假如实行var f = new F("warjiang");jsnew F('warjiang')的时刻回疏忽F的返回值。f末了是一个对象,而不是"F".实行效果以下:

《js面向对象基本》

什么时刻用prototype,什么时刻用this

接着上面的例子,我们在定义Cat类的时刻,关于name,color这些属性的定义是采纳的this的体式格局。而关于sayName,sayAge的定义是采纳的prototype的体式格局。那末什么时刻该用this,什么时刻该用prototype呢?在说这个题目之前,我想从新再提一下=====。置信每一个jser都应当晓得这个两个等号与三个等号的区分,两个等号只比较数值大小,不关心范例;三个等号不仅比较值大小,还要比较范例是不是一致。下面我们先看个例子:

// number范例
var num1 = 22;
var num2 = 22;
console.log(num1 == num2);//true
console.log(num1 === num2);//true


// string范例
var str1 = "hello world";
var str2 = "hello world";
console.log(str1 == str2)//true
console.log(str1 === str2)//true

// 对象
var student1 = {
    name:"tony",
    age:22
};
var student2 = {
    name:"warjiang",
    age:22
}
console.log(student1 == student2);//false
console.log(student1 === student2);//false

// Date范例
var d1 = new Date('2017-3-15 10:23:00');
var d2 = new Date('2017-3-15 10:23:00');
console.log(d1 == d2);//false
console.log(d1 === d2);//false;

// 自定义范例
function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.sayName = function(){
    console.log("my name is " + this.name);
}

var cat1 = new Cat("大黄","黄色");
var cat2 = new Cat("大黄","黄色");
console.log(cat1 == cat2);//false
console.log(cat1 === cat2);//false

经由历程上面的例子,我们能够总结出,在js中除了基础范例bool,string,number,undefined,null是根据value的体式格局举行相称的比较以外,其他的对象(不管是自定义的照样JS内置的)在做比较的时刻都是比较两个对象的内存地址,假如两个对象的内存地址不相称,则示意两个对象就是不相称的。所以才会涌现上面例子中的,纵然连个对象中一切的属性都相称,依然会涌现两个对象不相称的状况。
ok回到正题上了,有了这边等号比较的基础以后,我们在来看看之前的题目,什么时刻应当运用prototype,什么时刻应当运用this。再来个?

function Cat(name,color){
    this.name = name;
    this.color = color;
    this.sayColor = function(){
        console.log(this.color);
    }
}
Cat.prototype.sayName = function(){
    console.log("my name is:"+this.name);
}

var cat1 = new Cat("大黄","黄色");
var cat2 = new Cat("明白","白色");
console.log(cat1.sayColor == cat2.sayColor);//false
console.log(cat1.sayName == cat2.sayName);//true

上面例子中两个Cat范例的对象cat1,cat2在内存中是什么状况呢。
《js面向对象基本》

经由历程上面的内存图,我们能够晓得cat1sayColorcat2sayColor要领离别指向两块内存地址,所以cat1.sayColor==cat2.sayColorfalse,而cat1.sayNamecat2.sayName都是来源于prototype对象上的sayName要领,他们的内存地址实际上是一个,故而cat1.sayName == cat2.sayName要领为true
经由历程上面的两个例子,我们不难看出,假如我们运用this的话,则this上的属性、要领都是属于对象自身的,平常能够用于私有要领、属性,而假如运用prototype的话,prototype上的属性、要领在各个类对象上面同享,平常能够用于共有要领、属性。

因而关于一些共有的要领、属性,我们能够放在prototype上面,而关于一些私有的要领、属性,我们能够放在prototype上
下面的话,我再补充一个分外的例子

function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.sayType = function(){
    console.log(this.type);
}
var cat1 = new Cat("大黄","黄色");
var cat2 = new Cat("明白","白色");

cat1.sayType();//猫科动物
cat1.type = "狗科动物";
cat2.sayType();//猫科动物
cat1.sayType();//狗科动物

这边的话,能够有些同学会以为cat1.type = “狗科动物”这句话,修改的是prototype中的type,然则实际上cat1.type=”狗科动物”,只是在cat1对象上面增加了一个type属性,值为”狗科动物”,而原型上面的type并没有收到影响。我们能够在掌握台中检察cat1与cat2的细致以下:
《js面向对象基本》
假如想修改prototype中的type的话,能够把cat1.type修改为cat1.__proto__.type = "狗科动物"(这边也要注意下,__proto__并非一切浏览器都支撑);此时实行效果就像人人想的那样离别为猫科动物,狗科动物,狗科动物

JavaScript的继续

谈到js的继续,起首先了解下js中原型链。每一个js对象都有一个prototype的属性,这个属性会指向一个新的对象,这个新的对象也会有一个prototype的属性。如许一直到Object.
这边轻微提下,有些人能够会问浏览器中__proto__prototype的区分,能够理解为__proto__chrome、firefox这些浏览器对prototype的一种完成、表现,东西照样一个东西。原型链我也举个例子

var o = {
    name:'warjiang',
    age:24
}
var b = {
    name:'bb'
}
b.__proto__ = o;
console.log(b.name);//bb
console.log(b.age);//24
console.log(b.__proto__.name);//warjiang

讲完原型链,我们就最先最先讲讲继续。这边的话,我看也有人说用属性拷贝或者是要领借用这类体式格局来完成继续,不过我不是异常承认。这边我主要用讲原型来完成继续。
用原型链完成继续,就是让子类的prototype指向父类的prototype,比方下面如许:

function Parent(){
    this.type = "parent";
}
Parent.prototype.sayType = function(){
    console.log(this.type);
}

function Child(){
    
}
Child.prototype = Parent.prototype;
Child.prototype.constructor = Child;

然则假如如许写会有一个题目,就是我们在修改子类prototype的constructor的同时也修改了父类的prototype的constructor,这类状况是不允许的。那末处理的思绪平常就是两种,一个是经由历程new Parent()来处理,我们晓得new Parent()的历程帮我们制造一个prototype指向Parent的prototype的对象(记作o,o.prototype=parent.prototype),这个时刻,让子类prototype指向o这个对象的时刻,Child.prototype->o,o.prototype->Parent.prototype,如许一个原型链就这么链接起来了,同时这个时刻假如去修改Child.prototype.constructor为Child的时刻,相称于实行o.constructor = Child,并不会对Parent.prototype形成影响。这类做法的表现形式以下:

function Parent(){
    this.type = "parent";
}
Parent.prototype.sayType = function(){
    console.log(this.type);
}

function Child(){
    
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;

此时假如我们去new Child()对象的时刻,我们能够以下的继续图
《js面向对象基本》

剖析Child.prototype=new Parent();这个历程我们会发明,new Parent()实在对Parent的prototype起到庇护的作用,因而我们完全能够经由历程一个空对象来完成如许的功用,以下:

function Parent(){
    this.type = "parent";
}
Parent.prototype.sayType = function(){
    console.log(this.type);
}
var f = function(){}
f.prototype = Parent.prototype;
function Child(){
    
}
Child.prototype = new f();
Child.prototype.constructor = Child;

这么做的优点在于new f()的历程相关于new Parent()的历程越发轻量,越发勤俭内存。

参考

Prototye inheritance

Javascript 面向对象编程(一):封装

Javascript 面向对象编程(二):封装

Javascript面向对象编程(三):非组织函数的继续

    原文作者:warjiang
    原文地址: https://segmentfault.com/a/1190000008828839
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞