js 高程学习总结 第六章

来源:互联网 发布:高斯滤波算法实现 编辑:程序博客网 时间:2024/06/03 15:57

理解对象

对象字面量创建对象:

var person = {    name:'sdf',    sayname : function(){        console.log(this.name);    }}

1.属性类型
为表示特性是内部值,js不能直接访问它们,把它们放在两对方括号中,例如[[Enumerable]]
ECMAScript有两种属性:数据属性,访问器属性
数据属性
包含一个数据值的位置,可以读取和写入值,,有四个属性描述其行为:

  • [[Configurable]]:表示是否能通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性
  • [[Enumerable]]表示能否通过for-in循环返回属性
  • [[Writable]] 表示能否修改属性的值
  • [[Value]] 包含这个属性的数据值,读取属性值时,从这个位置读,写入属性值的时候,把新值保存在这个位置
    要修改属性的默认的特性,必须使用ECMAScript 5的Object.defineProperty()方法,这个方法接收三个参数,属性所在的对象、属性的名字和一个描述符对象(必须是configurable 、enumerable 、writable、value中的一个或几个值),

    var person = {};Object.defineProperty(person,"name",{    writable: false,    value: "Nicholas"});console.log(person.name);//"Nicholas"person.name = "Greg";//严格模式下将会报错person.name;//"Nicholas";
    var person = {};Object.defineProperty(person,"name",{    configurable : false,    value: "Nicholas"});//抛出错误Object.defineProperty(person,"name",{    configurable : true,    value: "Nicholas"});

    将某属性的configurable 设置为false后就不能修改该属性的特性了

访问器属性
访问器属性不包含数据值,只含一对getter和setter函数;
在读取访问器属性时,会调用getter函数,负责返回有效的值,在写入访问器属性时,会调用setter函数并传入新值,
访问器属性有四个特性

  • [[Configurable]]:表示是否能通过delete删除属性从而重新定义属性,能否修改属性的特性,或能否把属性修改为访问器属性
  • [[Enumerable]]表示能否通过for-in循环返回属性
  • [[Get]] 读取属性时调用的函数
  • [[Set]] 写入属性时调用的函数
var book = {    _year :2004,    edition : 1}Object.defineProperty(book,"year",{    get: function(){        return this._year;    },    set: function(newValue){        if(newValue > 2004){            this._year = newValue;            this.edition += newValue - 2004;        }    }})

book对象定义了两个默认的属性,_year和edition,_year 前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性,访问器属性year包含一个getter函数和setter函数,一般访问器属性的值这样使用:改变一个属性值会导致其他属性发生变化
严格模式下必须getter和setter同时指定

定义多个属性
Object.defineProperties()方法,可以通过描述符一次定义多个属性,这个方法接收两个对象参数:第一个为要添加和修改其属性的对象,第二个对象与第一个对象中要添加或修改的属性一一对应
读取属性的特性

Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符;接受两个参数:属性输在对象,要读取其描述符的属性名称,返回值是一个对象,如果是访问器属性,这个对象的属性有configurable,enumerable,getset,如果是数据属性,这个队形的属性有configurable,enumerable,writable和value;其中value初始值为undefined,get set为undefined,其余为false

创建对象

用构造函数或对象字面量可以用来创建单个对象,但是有明显缺点,会产生大量的重复代码,为解决这个问题
工厂模式

function ceateperson(name,age,job){    var o = new Object();    o.name = name;    o.age= age;    o.job= job;    o.sayName = function (){        console.log(this.name)    }    return o;}var person = createperson('Nickho',29,'sdfsdfdsf')

解决了重复代码的问题,但是没有解决对象的识别问题(即知道一个对象的类型)

构造函数模式
构造函数应以一个大写字母开头,非构造函数以小写字母开头

function Person(name,age,job){    this.name = name;    this.age= age;    this.job= job;    this.sayName = function (){        console.log(this.name)    }}var person1 = new Person('Nickho',29,'sdfsdfdsf')

new调用构造函数会经历一下4个步骤

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(因此this就指向这个新对象)
  • 执行构造函数中的代码(为这个新对象添加属性)
  • 返回新对象
    person1.constructor == Person ;// true
    对象的constructor属性时用来标识对象类型的,检测对象类型,还是instanceof操作符更可靠 person1 instanceof Person ;// true

将构造函数当做函数
任何函数,只要能通过new来调用,就可以把它作为构造函数;没通过new来调用,就是普通函数;如Person(‘Nickho’,29,’sdfsdfdsf’)//就是当做普通函数调用的,添加到window

var o = new Object();Person.call(o,"kristen",25,"nurse")o.sayName()//在o的作用域调用,调用后o具有所有的属性和sayName方法

构造器函数缺点::每个方法都要在每个实例上重新创建一遍
可以把函数定义转移到构造函数外部来解决这个问题。但是会出现新的问题,全局函数只能被某个函数调用,如果有很多方法就要定义很多全局函数,,没有封装性可言,那就引出了原型模式

原型模式
每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用于是包含可以由特定类型的所有实例共享的属性和方法;可以让所有对象实例共享它所包含的属性和方法;不用再构造函数中定义对象实例的信息,而是将这些信息直接添加到原型对象中

function Person(){}Person.prototype.name = 'Nicholas';Person.prototype.sayName = function (){}var person1 = new Person();var person2 = new Person();person1.sayName == person2.sayName;//true;

Person.prototype.isPrototypeOf(person1);//true
Person.prototype.isPrototypeOf(person2);//true
每当代码读取某个对象的某个属性时,都会执行搜索,首先查询对象实例本身,如果找到了则返回,如果没找到,则继续搜索指针指向的原型对象;
当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性,而不会修改原型中的属性,即使在对象实例中设置这个属性为null,也不会访问原型中的属性,可以通过delete操作符完全删除实例属性,从而重新访问原型中的属性

hasOwnProperty 方法可以检测一个属性是存在于实例中还是原型中,只有在属性存在于实例中时,才会返回true;

原型与in操作符
in两种使用方法:单独使用和for-in循环中使用。单独使用时,in会在通过对象能访问给定属性时返回true,无论在实例中还是在原型中(可以和hasOwnProperty结合使用,确定属性在对象还是原型);

function hasPrototypeProperty(object,name){    return !object.hasOwnProperty(name) && (name in object);}

for-in 循环时,返回的是能所有能通过对象访问的、可枚举(enumerated)属性,其中既包括实例中的属性,也包括存在于原型中的属性
取得对象上所有可枚举的实例属性,Object.keys()方法会就接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数值(例如Person.prototype或者person1)
获取所有的实例属性,无论是否可枚举Object.getOwnPropertyNames(Person.prototype)//["constructor", "name", "sayName"]

原型的动态性
由于在原型查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能立即从实例上反映出来,即使先创建了实例后修改原型也是如此;

function Person(){}var fri = new Person();Person.prototype.sayName = fucntion(){}friend.sayName();//okPerson.prototype = {    constructor: Person,    sayName: function(){}}friend.sayName();//error

但是如果重写了整个原型对象,情况就不一样了,构造函数会为实例添加一个指向最初原型的指针,而把原型修改为另一个对象就等于切断了构造函数和最初原型之间的联系,实例中的指针仅仅指向原型,不是指向构造函数
但是原型模式也会有一个问题,如果属性是基本类型的话,可以通过在实例中添加 一个同名属性,但是如果是引用类型的话,就会造成所有的实例都包含同一个引用类型,因此很少单独使用原型模式

0 0
原创粉丝点击