美文网首页
javascript高级程序设计读书笔记(五)

javascript高级程序设计读书笔记(五)

作者: youngiyang_打码少年 | 来源:发表于2016-09-08 13:48 被阅读28次

面向对象的程序设计

NO.1 对象

OO语言都有一个标志,就是都有类的概念,通过类可以创建多个具有相同属性的方法的对象。但JS里没有类的概念,所以它的对象也有所不同。JS把对象定义为无序属性的集合。

JS的每个对象都是基于一个引用类型创建的。

JS中有两种属性,数据属性和访问器属性;
1.数据属性:
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有四个描述其行为的特性:
Configurable:表示能否通过delete删除属性从而重新定义属性。
Enumerable: 表示能否通过for-in循环返回属性。
Writable: 表示能否修改属性的值。
Value: 包含这个属性的数据值。

这四个是对象的默认属性。要修改默认是属性的特性,可以用Object.defindProperty()方法.例如:把属性定义为只读,把属性定义为不能删除等。

var book = {
_year: 2004,
edtion: 1
}
_year是一种常见的记号,表示中能通过对象方法访问的属性。

创建对象:
虽然Object构造函数和字面的方法都可以用来创建单个对象,但是这些方法都有明显的缺点,就是当一个接口创建很多对象时,会有很多重复代码。为了解决这个问题,人们使用工厂模式的一种变体。

工厂模式抽象了创建对象的具体过程,例如:

function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    p.age = age;
    o.job = job;
    o.sayname = function(){
        alert(this.name);
    };
    return o;
}

工厂模式虽然解决了对个类似对象的问题,但是没有解决对象识别问题(怎么样知道一个对象的类型)。于是有了构造函数模式:

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };
}

var person1 = new Person("yzq", 25, "software engineer");

构造函数:
构造函数和其他的函数的唯一区别是调用的方式不同,构造函数都是通过new来调用的。

构造函数的问题:
构造函数虽然好用,但是在用构造函数创建对象时,当对象有方法时,就需要在每个构造函数里创建一个方法。为了解决这一个问题。将函数定义转移到构造函数的外面:

function Person(name,age,job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName
}
function sayName(){
        alert(this.name);
};

var person1 = new Person("yzq", 25, "software engineer");
        

原型模式:
我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,这个对象包含由特定类型所有实例共享的属性和方法。
例子:
function Person(){};
Person.prototyoe.name = "yzq";
Person.prototyoe.age = 25;
Person.prototyoe.job = "cc"
Person.prototyoe.sayName = function(){
alert(this.name);
};

var person1 = new Person();
person1.sayName(); //"yzq"

var person2 = new Person();
person2.sayName(); //"yzq"
通过这种方式,将属性和方法共享。

理解原型对象:
1.只要一个新函数被创建时,就会根据一组的特定的规则为该函数创建一个prototype属性。
2.这个prototype属性是一个指针,指向函数的原型对象。
3.然后在默认情况下,原型对象都会自动获得一个构造函数属性。这个属性是指向prototype属性所在函数的指针。例如:Person.prototype.constructor指向Person
通过构造函数,可以继续为原型对象添加其他属性和方法。
4.在创建了自定义的构造函数之后,其原型对象默认只会取得constructor。其他方法,都是从Object继承而来
5.当用构造函数创建了一个新实例后,实例内部将包含一个指针为[[Prototype]]

个人理解:
Person.prototype指向原型对象,原型对象的构造函数Person.prototype.constructor又指回了Person。原型对象中除了包含构造函数属性之外,还有其他的属性。
而真正的每个实例都包含一个内部属性,数值只指向Person.prototype。实例和构造函数是没有任何直接联系的。

当代码读取某个对象的某个属性时,都会先从对象实例本身开始,如果在实例本身中找到了给定的名字的属性,则返回属性的值,如果找不到,则继续搜索指针指向的原型对象。例如:在调用person1.sayName()的时候,在person1中没有找到sayName属性,但是在person1的原型中有sayName属性。

另外,当对象实例可以访问原型中的属性,但是不能重写原型中的属性。所以当对象实例中有原型中的同名属性时,实例中的该同名属性会屏蔽原型里的属性。要想重新访问原型里的属性,可以用DELETE删除实例中的属性。

NO.2 原型和in操作符

有两种方式使用in操作符,单独使用和在for-in循环中使用。
单独使用时,in操作符会通过对象能够访问给定属性时,返回true。无论该属性存在实例还是原型中。

alert("name in person1")一直都是true,当属性存在时。不管在实例中还是原型对象里。

要想确定属性在对象中还是存在原型中,可以同时使用hasOwnProperty()和in操作符。方法如下:
function hasPrototypeProperty(object, name)[
return !object.hasOwnproperty(name) && (name in object);
}
hasOwnproperty只有在实例中才返回true。所以以上那个函数为true时,可以判断属性是在原型中。

要获取对象上所有可枚举的实例属性,可以使用Object.keys()方法。这个方法接受一个对象作为参数,返回一个所有属性的字符串数组

var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName"

var p1 = new Person()
p1.name = "yzq"
p1.age = 25;
var p1keys = Object.keys(p1);
alert(p1keys); // "name,age"

更简单的原型语法:

function Person(){
}
Person.prototype = {
    name : "yzq",
    age : 25,
    sayName : function(){
        alert(this.name);
    }
}

注意:使用上面语法会导致constructor的属性等于Object而不等于Person了。
如果constructor真的很重要,可以自己定义。

function Person(){
}
Person.prototype = {
    constructor : Person,
    name : "yzq",
    age : 25,
    sayName : function(){
        alert(this.name);
    }
}

NO.3原型的动态性

先创建实例,在修改原型,指在原型里添加属性和方法。这样是OK的。

var friend = new Preson();
Person.prototype.sayHi = function(){
 alert("hi");
}
friend.sayHi(); //"hi"

但是先创建实例,在重新写整个原型。这样就会报错。

function Person(){
}
var friend = new Preson();
Person.prototype = {
    constructor : Person,
    name :"yzq",
    age :25,
    sayName: function(){
        alert(this.name);
    }
}

friend.sayName(); //error

NO.4原型模式的缺点

因为原型模式中的属性和方法都是共用的,所以,当一个实例修改原型模型中的属性时,其他实例中的属性也会改变。

所以原型模式和构造函数模式一般是组合使用:


NO.5 动态原型模式

为了解决同时写构造函数和原型这个问题,于是出现了动态原型模式。

function person(name,age,job){
    //属性
    this.name = name;
    this.age = age;
    this.job = job
    //方法
    if (typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            alert(this.name);
        };
    }
}

typeof this.sayName != "function"指的是当sayName方法不存在的时候,将方法放入原型中。

相关文章

网友评论

      本文标题:javascript高级程序设计读书笔记(五)

      本文链接:https://www.haomeiwen.com/subject/gnmsettx.html