《JavaScript高级语言设计》(第三版)学习笔记(3)

来源:互联网 发布:网络教育学籍注册冲突 编辑:程序博客网 时间:2024/06/11 14:09

面向对象的程序设计和函数表达式(重要)

1.数据类型
1.1数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性

特性 含义 [[Configurable]] 表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为true [[Enumberable]] 表示能否通过for-in循环返回属性,默认值为true [[Writable]] 表示能否修改属性值,默认为true [[Value]] 包含这个属性的数据值,在读取属性值时,从这个位置读,写属性值时,从这个位置保存值,默认为undefined

修改属性默认的特性,使用Object.defineProperty()方法,在调用该函数时,如果不指定,则四个属性都为false IE8+
例子:

var person = {};Object.defineProperty(person,"name",{    writable:false,//严格模式下个name赋值抛出错误    configurable:false,//设置不可通过delete删除属性,严格模式下delete会抛出错误,该属性不可多次设置,会报错    value:"张三",});delete person.name;//不可删除

1.2访问器属性
访问器属性不包含数据值,白喊一对getter和setter函数

特性 含义 [[Configurable]] 表示能否通过delete删除属性,默认为true [[Enumerable]] 能否通过for-in循环返回属性,默认为true [[Get]] 在读取属性是调用的函数,默认值undefined [[Set]] 写入属性调用的函数,默认为undefined

必须使用Object.defineProperty()

var book = {    _year : 2004,    edition : 1};Object.defineProperty(book,"year",{        get : function(){            return this._year;        },        set : funcion(newValue){            if(newValue > 2004){                this._year = newValue;                this.edition += newValue - 2004;            }        }});book.year = 2005;alert(book.edition);//2

版本支持:IE9+(IE8 只是部分实现)、Firefox 4+、Safari 5+、Opera12+ 和Chrome
老的非标准方法 版本支持:Firefox,Safari 3、Chrome 1 和Opera 9.5

对象._defineGetter_("属性名",方法)对象._defineSetter_("属性名",方法)

1.3一次性定义多个属性
版本支持:IE9+、Firefox 4+、Safari 5+、Opera 12+和
Chrome。

var book = {};Object.defineProperties(book,{    _year:{        value:2004    },    edition:{        value:1    },    year:{        get:function(){            return this._year        },        set:function(){            if(newValue > 2004){                this._year = newValue;                this.edition += newValue-2004;            }        }    }})

1.4读取属性特性
版本支持:IE9+、Firefox 4+、Safari 5+、Opera 12+和Chrome。
Object.getOwnPropertyDescriptor(),获取给定属性描述符:接受两个参数:对象,属性名称,返回包含访问器属性或数据属性的对象

2.创建对象
2.1工厂模式

function createPerson(name,age,job){    var o = new object();    o.name = name;    o.age = age;    o.job = job;    o.sayName = function(){        alert(this.name);    };      return o;}var person1 = createPerson("Nicholas",29,"Software Engineer");

2.2构造函数模式

function Person(name,age,job){    this.name = name;    this.age = age;    this.job = job;    this.sayName = function(){        alert(this.name);    };}var person1 = new Person("Nicholas", 29, "Software Engineer");var person2 = new Person("Greg", 27, "Doctor");

person1和person2分别保存着Perosn的一个不同的实例。这恋歌对象都有一个constructor属性,该属性指向Person
问题:每个方法都要在实例上重新创建一遍,会导致不同的作用域链和标识符解析也就是person1.sayName与person2.sayName不等价

2.3原型模式
每个函数都有prototype(原型)属性,这个属性就是一个指针,指向包含可以有特定类型的所有实例共享的属性和方法的对象

function Person (){}Person.prototype.name = "张三";Perosn.prototype.age = 29;Person.prototype.job = "software Engineer";Person.prototype.sayName = function(){alert(this.name);};

理解原型,创建函数,会根据特定规则为该函数创建一个prototype属性,该属性指向函数的原型。原型有一个constructor属性,该属性包含一个指向prototype属性所在函数的指针
这里写图片描述

Object.getPrototypeOf()方法返回[[Prototype]]的值
版本支持IE9+、Firefox 3.5+、Safari 5+、Opera 12+和Chrome

读取对象属性执行过程
每当读取摸个对象的摸个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象的实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果还没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。如果在原型对象中找到了这个属性,则返回该属性的值。
不可以通过对象实例重写原型中的值

2.4原型与in操作符
使用in操作符的两种方式1.单独使用表示能否访问对象的特定属性,2.for-in循环
确定为原型属性
hasOwnProperty()返回false,in返回true

取得对象上的所有可枚举的实例属性:Object.keys(原型)或Object.getOwnPropertyNames(原型)返回属性组成的字符串,版本支持IE9+、Firefox 4+、Safari5+、Opera12+和Chrome。

2.5简单的原型语法

function Perosn(){}Person.prototype = {    constructor:Person,//会导致Enumerable的特性被设置为true    name : "张三",    age : 29,    job : "Enginner".    sayName : function(){        alert(this.name);    }}//重构造函数,只适用于ECMAScript5兼容的浏览器Object.defineProperty(Person.prototypr,"constructor",{    enumerable:false,    value:Person});

重写原型对象不会切断原始原型与任何之前已经存在的对象实例之间的联系。
缺点:共享本质与java的static类似

2.6.组合使用构造函数和原型模式

function Perosn(name,age,job){    this.name = name;    this.age = age;    this.job = job;    this.friends = ["A","B"];}Perosn.prototype = {    constructor : Person,    sayName : function(){        alert(this.name);    }}

2.7动态原型模式

function Perosn(name,age,job){    this.name = name;    this.age = age;    this.job = job;    if(typeof this.sayName != "function"){        Person.prototypr.sayName = function(){        alert(this.name);        }    }}

2.8寄生构造函数模式
依托于o的基础上

function Person(name,age,job){    var o = new Object();    o.name = name;    o.age = age;    o.job = job;    o.sayName = function(){        alert(this.name);    }    return o;}

2.9稳妥构造函数模式
不是用this

3.继承
接口继承和实现继承
3.1原型链
实现继承的主要方法
利用原型让一个引用类型继承另一个引用类型的属性和方法
大致代码如下

function SuperType(){    this.proper= true;}SuperType.prototype.getSuperValue = function(){    return this.proper;};function SubType(){    this.subproper = false;}//继承SubType.prototype = new SuperType();SubType.prototypr.getSubValue = function(){    return this.subproper;};

这里写图片描述

上图中少了Object的原型
这里写图片描述
instanceof操作符测试实例与原型链中出现过的构造函数,结果都会返回true
原型链的问题
包含被引用类型值的原型和不能向超类的构造函数传递参数
3.2借用构造函数
在子类型构造函数的内部调用超类型的构造函数

function SuperType(){    this.color = ["red","blue","green"];}function SubType()(){    //继承SuperType    SuperType.call(this);}

有点可以向超类中传递参数
3.3组合继承
伪经典继承,指将原型链和借用构造函数的技术组合到一块

function SuperType(name){    this.name = name;    this.color = ["red","blue","green"];};SuperType.prototype.sayName = function(){    alert(this.name);};function SubType(name,age){    SuperType.call(this,name);    this.age = age;}SubType.prototypr = new SuperType();SubType.prototype.constructor = SubType;SubType.prototype.sayAge = function(){    alert(this.age);}

3.4原型式继承

function object(o){    function F(){};    F.prototype = o;    return new F();}

object()对传入其中的对象执行了一次浅复制
ECMAScript5增加Object.create()规范原型式继承
版本支持IE9+、Firefox 4+、Safari 5+、Opera 12+和Chrome

var person = {    name:"张三",    friedns:["A","B","C"]}var anotherPerson = Object.create(person);var anotherPerson1 = Object(person);var anotherPerson2 = Object.create(person,{    name:{        value:"Grey"    }});

3.5寄生式继承

function createAnother(o){    var clone = object(o);    clone.sayHi = function(){    alert("hi")    };    return clone;}

3.6寄生组合式继承
不必为了指定子类型的原型而调用超类型的构造函数,本质上是就是使用寄生式继承来继承超类类型的原型,然后将结果指定给子类型的原型
基本模式如下

function inheritPrototype(subType,superType){    var prototype = object(superType.protype);//创建超类原型的一个副本    prototype.constructor = subType;//为副本添加constructor属性    subType.prootype = prototype;//将对象赋值给子类原型}

4.函数表达式
name属性,函数的名称,版本支持Firefox、Safari、Chrome
和Opera
函数声明提升
在执行代码之前会读取函数声明,意味着函数声明可以放在调用语句后面

var f = function(arg0){//函数体};//这种形式为创建一个匿名函数并赋值给f,这种方式没有函数声明提升

4.1递归
可使用arguments.callee实现对函数的递归调用

function factorial(num){    if(num < 1){        return 1;    } else{        return num*arguments.callee(num-1);    }}

4.2闭包(##重要##)
闭包:闭包是指有权访问另一个函数作用域中的变量的函数
常见的闭包创建方式,在一个函数内部创建另一个函数

function createComparisonFunction(propertyName){    return function(object1,object2){        var value1 = object1[properyName];//函数内部访问外部属性,返回后依然可访问        var value2 = object2[propertyName];//        if(value1 < value2){            return -1;        }else if(value1 > value2){            return 1;        }else{            return 0;        }    };}

在这个例子中,突出的两行代码是内部函数中的代码,这两行代码访问了外部函数中的变量propertyName。即使这个内部函数被返回了,而且是在其他地方被调用了,但他仍然可以访问变量propertuName。内部函数的作用域链中包含createComparisonFunction()的作用域
当某个函数被调用时,会创建一个执行环境及对应的作用域链。然后,使用arguments和其他命名参数的值来初始化函数活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数处于第三位。。。直到全局环境变量
例子

function compare(value1,value2){    if(vallue1 , value2){        return -1;    }else if(value1 > value2){        return 1;    }else{        return 0;    }}var result = compare(5,10);

这里写图片描述

闭包的情况:当createComparisonFunction()执行后,作用域链中的全局变量对象被销毁,但其活动对象不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。
这里写图片描述

4.3 闭包与变量
闭包只能取得包含函数中任何变量的最后一个值

function createFunctions(){    var result = new Array();    for(var i =0 ; i < 10; i++){        result[i] = function(){//包含createFunctions的活动对象,如果在函数外部调用取得i为createFunction的活动对象的值为10            result i;        };    }    return result;}
function createFunctions(){    var result = new Array();    for(var i =0 ; i < 10; i++){        result[i] = function(num){//闭包1            retrun function(){//闭包2在createFunctions的前端又加了一个匿名函数活动对象,这个活动对象存入num值为索引值                return num;            };        }(i);    }    return result;}

4.4this对象
匿名函数的执行环境具有全局性,因此this对象通常指向window
在闭包中获取外部函数的this对象

var name = "The Window";var Object = {    name : "My Object";    getNameFunc : function(){        var that = this;        return fnction(){            return that.name;        }    }}

4.5内存泄漏
如果闭包的作用域链中保存着一个HTMl元素,则意味意味着该元素无法被销毁,引用后手动销毁设置为null

4.6模仿块级作用域

(function(){//这里是块级作用域})();

4.7私有变量
任何在函数中定义的变量都可以认为是私有变量
静态私有变量
在js中定义一个类

(function(){    var name = "";//此为共有变量    Person = function(value){        name = value;    };    Person.propertype.getName = function(){        return name;    };    Person.propertypr.setName = function(value){    name = value;    };})();var person1 = new Person("张三");alert(person1.getName());//张三

4.8模块模式
为单例创建私有变量和特权方法
js以对象字面量创建单例对象

var sigletion = {    name : value,    method :function(){        //方法    }}

增强后

var sigleton = function(){    //私有变量和函数    var privateVariable = 10;    var components = new Array();    function privateFunction(){        return false;    }    //共有方法和函数    return {        publicProperty:true,        publicMethod:function(){            privateVariable++;            return privateFunction();        }    }}
0 0
原创粉丝点击