js学习笔记(一)

基于《javaScript高级程序设计》1-6章学习笔记

DOM,文档对象模型,提供访问和操作网页内容的方法和接口。
BOM,浏览器对象模型,提供与浏览器交互的方法和接口。

HTML中使用js

基本概念

js区分大小写
严格模式:为js定义一种不同的解析与执行模型,ECMAScript3中的一些不确定行为得到处理,不安全操作抛出错误。顶部添加"use strict"启动。
let,yield第5版新增保留字。
var 定义的变量将成为该变量的作用域中的局部变量。
在一个作用域范围内,无论变量在哪个位置声明,都将申明提升到范围顶部(不涉及赋值)。

if(!"a" in window){
    var a = 1;
}
alert(a);  //undefined

数据类型:undefine,null,boolean,number,string,object
typeof操作符,检测给定变量的数据类型。
对未初始化或未声明的变量执行typeof都返回undefined。
如果定义的变量准备将来用于保存对象,最好将其初始化为null。
null == undefined //true
八进制第一位为0,如果字面值超出数值,前零忽略,后面的值被当做十进制处理。
var octalNumber = 079; //无效八进制–解析为79
浮点数需要的内存空间是保存整数值的两倍,js会不时将浮点值转成整数值。
浮点数算数计算,存在精度问题。js中数字采用64位双精度浮点数,计算时转换成二进制计算,而浮点数的二进制是无限的;又因为小数点限制截断二进制,再转换为十进制,导致数值异常。

0.1+0.2 = 0.30000000000000004 

非数值转换为数值:Number(),parseInt(),parseFloat()
es中字符串不可变,改变某个变量保存的字符串,首先要销毁原先字符串,用新值填充。(类似java中的String机制)
Object的属性和方法:
constructor:保存着用于当前对象的函数。
hasOwnProperty(propertyName):检查给定的属性在当前对象实例中是否存在。
isPrototypeOf(object):检查传入的对象是否是当前对象的原型。
toLocaleString():返回对象的字符串表示,与执行环境的地区对应。
toString()
valueOf()
BOM和DOM中的对象属于宿主对象,由宿主对象实现提供和定义,可能会也可能不会继承Object
负数以二进制码存储,使用的格式是的二进制补码。
求二进制补码步骤:
1.求这个数值绝对值的二进制码
2.求二进制反码。即将0替换为1,将1替换为0
3.得到的反码加1。
es中应用位操作符时,将64位数值转为32位,执行位操作,将32位转换回64位。

"55"== 55 //true 相等操作符,转换后相等
"55" === 55 //false 全等操作符,数据类型不相等
"55" != 55 //false 不相等操作符,,转换后相等
"55" !== 55 //true 不全等操作符,数据类型不相等

for-in语句返回的先后顺序可能会应浏览器而异。
es中的参数在内部是用一个数组来表示,函数体内可以通过arguments对象来访问这个参数数组(arguments[0]…),从而获取传递给函数的每一个参数。

变量、作用域和内存问题

基本类型:undefined,null,boolean,number,string;可以操作保存在变量中的实际的值。
引用类型:值是保存在内存中的对象,js不允许直接访问内存中的位置,不能操作对象的内存空间。
引用类型当复制保存着对象的某个变量时,操作的是对象的引用;为对象添加属性时,操作的是实际的对象。
从一个变量向另一个变量复制基本类型的值,双方互不干扰。
从一个变量向另一个变量复制引用类型的值,两个变量实际引用同一个对象。
es中函数的参数都是按值传递。

function setName(obj){
    obj.name = "name1";  
}
var persion = new Object();
setName(persion);   //persion复制给obj,obj和persion引用的是同一个对象
alert(persion.name); //"name1" 
function setName(obj){
    obj.name = "name";
    obj = new Object();
    obj.name="name2";
}
var persion = new Object();
setName(persion);   //参数按值传递,obj重新定义了一个对象。
alert(persion.name); //"name1"

typeof检测基本数据类型,instanceof检测引用类型。
with语句会将指定的对象添加到作用域链中。
js没有块级作用域。if语句中的变量声明会将变量添加到当前的执行环境。

if(true){
    var color = "blue";
}
alert(color); //"blue"
for(var i=0;i<10;i++){
    doSomething(i);
}
alert(i); //10

初始化变量时没有var申明,变量会添加到全局环境。

function add(num1,num2){
    var sum = num1 +num2;
    return sum;  //局部变量
}
function add(num1,num2){
    sum = num1 +num2;
    return sum;  //全局变量
}

js中最常用的垃圾收集方式是标记清除。给存储在内存中的所有变量加上标记。
不常见的垃圾收集策略是引用计数。跟踪记录每个值被引用的次数。存在循环引用的问题。
将变量设置为null意味着切断变量与它此前引用的值之间的连接。垃圾收集器下次运行时会删除这些值并回收他们的内存。
IE的垃圾收集器是根据内存分配量运行的,256个变量,4986个对象(或数组)字面量和数组元素,64kb的字符串,达到一个触发垃圾收集器。
IE7重写垃圾收集器,临界值调整为动态修正,初始与IE6相等,回收内存分配量低于15%,临界值加倍;高于85%,临界值重置。

引用类型

创建Object实例方式有2种:new操作符,对象字面量。

var persion ={
    name:"Nicholas",
    age:29
}

访问对象属性使用点表示法,也可以使用方括号

alert(person["name"]);
alert(person.name);

方括号的主要优点是可以通过变量来访问属性。
es数组的每一项可以保存任何类型的数据,大小可以动态调整。
Array.isArray()检测数组。
join()使用不同的分隔符构建字符串。

var colors = ["rea","green","blue"];
alert(color.join(","));  //red,green,blue
alert(color.join("||")); //red||green||blue

es数组行为类似于栈,push推入,pop推出,返回数组长度。shift()移除数组第一个项,unshift()数组前端添加任意项。
reverse()反转数组项顺序。
sort()比较字符串,可传入比较函数。

var colors =["red","green","blue","white","purple"];
var colors2 = colors.concat("yellow",["black","brown"]);  //red,green,blue,white,purple,yellow,black,brown
var colors3 = colors.slice(1);  //green,blue,white,purple
var colors4 = colors.slice(1,4);  //green,blue,white
var colors5 = colors.splice(0,2);  //blue,white,purple     删除前两项
var colors6 = colors.splice(2,0,"red","green");   //red,green,red,green,blue,white,purple 数组2的位置开始插入
var colors7 = colors.splice(2,1,"red","green");   //red,green,red,green,white,purple 删除数组2,从数组2插入

indexOf(),lastIndexOf()查找特定项在数组中的位置。
数组迭代方法:
every():数组每一项运行给定函数,每一项返回true才返回true
filter():数组每一项运行给定函数,返回函数会返回true的数组
forEach():数组每一项运行给定函数,没有返回值
map():数组每一项运行给定函数,返回每次调用的结果数组
some():数组每一项运行给定函数,有一项返回true,就返回true
归并方法:reduce(),reduceRight(),reduce()从第一项开始,reduceRight()从最后一项开始

var values = [1,2,3,4,5];
var sum =vlaues.reudce(function(prev,cur,index,array){   //function(前一个值,当前值,项的索引,数组对象)
    return prev+cur;
});
alert(sum);  //15

正则表达式匹配模式三个标志:
g:全局模式,应用于所有字符串
i:不区分大小写模式
m:多行模式,到达文本末尾时,还会继续查找
函数声明在执行任何代码之前可用(可以访问);函数表达式必须等到解析器执行到它所在的代码行,才能被解释执行。

alert(sum(10,10));   //可以运行
function sum(num1,num2){     //函数声明
     return num1+num2;
}
alert(sum(10,10));      //不能运行
var sum = function(num1,num2){   //函数表达式
    return num1+num2;
}

callSomeFunction(someFunction,someArgument);通用函数,第一个参数是一个函数,第二个是传递给该函数的一个值。返回执行第一个参数的结果。
arguments类数组对象,包含传入函数中的所有参数。主要用途保存函数参数。
argument的callee属性,是一个指针,指向拥有这个arguments对象的函数。

function factorial(num){   //递归算法 阶乘 消除耦合 无论函数使用什么名字都可以正常完成递归调用
    if(num<1){
        return 1;
    }else{
        return num * arguments.callee(num-1);
    }
}

this引用的是函数执行的环境对象。
函数对象属性caller保存着调用当前函数的函数的引用。

function outer(){
    inner();
}
function inner(){
    alert(inner.caller);
}
outer();      //显示outer()函数的源代码,因为outer()调用inner(),所以inner.caller指向outer()

es中函数是对象,包含2个属性length,prototype
length属性表示函数希望接受的命名参数的个数。
prototype不可枚举,使用for-in无法发现。
每个函数都包含两个非继承来的方法:apply(),call()用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

function sum(num1,num2){
    return num1 +num2;
}
function applySum(num1,num2){
    return sum.apply(this,argumnets);
}
function callSum(num1,num2){
    return sum.call(this,num1,num2); //apply() call()结果没有什么不同,只是接受参数的方式不同
}

apply()和call()真正强大的地方是能够扩充函数赖以运行的作用域。

window.color = "red";
var o = {color:"blue"};
function sayColor(){
    alert(this.color);
}
sayColor();                 //red
sayColor.call(this);        //red   显示地在全局作用域下调用函数
sayColor.call(window);      //red   显示地在全局作用域下调用函数
sayColor.call(o);           //blue  函数体内的this指向o

call()或apply()来扩充作用域的最大好处是对象不需要于方法有任何耦合关系。
bind()函数创建一个函数的实例,其this值会被绑定到传给bind()函数的值。
引用类型和基本包装类型的主要区别是对象的生存期。
new操作符创建的引用类型实例在执行流离开当前作用域之前都保存在内存中;自动创建的基本包装类型的对象,只存在一行代码执行瞬间,然后立即销毁。

var si = "some text";     //可以看成 var si = new String("new text")
si.color =red ;
alert(si.color);  //undefined si被销毁了,重新创建了一个String,没有color属性

toFixed()会按照指定的小数位返回数值的字符串表示。
字符串方法:
charAt():返回给定位置的字符
charCodeAt():返回给定位置的字符编码
concat():字符串拼接
slice(),substr(),substring():返回被操纵字符串的一个子字符串
indexOf(),lastIndexOf():查找子字符串
trim():删除前缀后缀的空格
match():返回数组,传入正则或RegExp
search():返回第一个匹配项的索引
replace():替换子字符串,第一参数RegExp或字符串,第二参数字符串或函数,替换所有字符串要提供一个正则指定全局标志
htmlEscape():可以转移4个字符<>&"",输出HtmL
split():指定分隔符分割字符串
fromCharCode():接收字符编码转换成一个字符串
内置对象:由es实现提供,不依赖宿主环境的对象。如Object,Array,String,Global(全局对象),Math
URI编码方法,encodeURI(),encodeURIComponent()
encodeURI():主要用于整个URI,不会对属于URI的特殊字符进行编码。相反decodeURI()
encodeURIComponent():主要对查询字符串,会使用对应的编码替换所有非分母数字字符。相反decodeURIComponent()
eval():将传入的参数当做es语句解析,结果插入原位置。被执行的代码具有与执行环境相同的作用连。
eval()中创建的任何变量或函数不会被提升。
在全局作用域中声明的变量和函数都成为window对象的属性。

面向对象的程序设计

对象的定义:无序属性的集合,其属性可以包含基本值、对象或者函数。
ES5中有两种属性:数据属性和访问器属性。
数据属性:
configurable:能否通过delete删除属性,能否修改属性特性,能否修改为访问器属性。直接在对象上定义默认true
enumerable:能否通过for-in循环返回属性,直接在对象上定义默认true
writable:能否修改属性的值,直接在对象上定义默认true
value:这个属性的数据值
修改属性默认的特性,使用es5的Object.defineProperty()

var perso={};
Object.defineProperty(person,"name",{
    writable:false,
    value:"newName"
})
alert(person.name);  //newName
person.name="changeName";
alert(person.name);    //newName

调用Object.defineProperty()创建属性时,不指定时,configurable,enumerable,writable默认false
访问器属性:configurable,enumerable,get,set
访问器属性不能直接定义,必须使用Object.defineProperty()来定义。
属性前面加下划线如_value,是一种常用的记号,表示只能通过对象方法访问的属性。
使用访问器属性的常见方式即设置一个属性的值会导致其他属性发送变化。
只指定getter意味着属性不能写,只指定setter意味着不能读。
es5中通过Object.getOwnPropertyDescription(),可以取得给定属性的描述符。
工厂模式抽象了创建具体对象的过程。解决了创建多个相似对象的问题,但没有解决对象识别的问题(即怎样知道对象的类型)。

//工厂模式
function createPerson(name,age){
    var o = new Object(); //显示创建对象
    o.name= name;
    o.age =age;
    return o;
}
var person1 = createPerson("name",15);

es中的构造函数可用来创建特点类型的对象。但主要缺点是每个方法都要在每个实例上重新创建一遍。

//构造函数模式
function Person(name,age){  //构造函数以一个大写字母开头,非构造函数小写字母开头
    this.name =name;   //将构造函数的作用域赋值给新对象,this指向这个新对象
    this.age =age;
}
var person1 = new Person("name",15);
alert(person1.constructor == Person);  //true
alert(person1 instanceOf  Person);  //true

每个函数都有prototype属性,这个属性是一个指针,指向一个对象用途是包含可以由特定类型的所有实例共享的属性和方法。
使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。

//原型模式
function Person(){
}
Person.prototype.name="name";
var person1 =new Person();
var person2 =new Person();
alert(person1.name);//name
alert(person2.name);//name

原型对象会自动获得constructor属性,指向prototype属性所在函数的指针。即Person.prototype.constructor指向Person,可以继续添加属性。
使用Object.getPrototypeOf()可以方便地取得一个对象的原型。
对象实例属性会先从本实例查找,没有才会去原型中查找。

function Person(){
}
Person.prototype.name="name";
var person1 =new Person();
var person2 =new Person();
person2.name ="newName";
alert(person1.name);//name
alert(person2.name);//newName
delete person2.name;  //delete 操作符可以删除实例属性
alert(person2.name);//name
alert(person2.hasOwnProperty("name"));//false 检测一个属性是否存在实例中
alert("name" in person2);//true 无论属性存在于实例还是原型中,能访问到返回true

不可枚举属性的实例属性也会在for-in中返回。
Object.keys()取得对象上所有可枚举的实例属性。
Object.getOwnPropertyNames()取得所有实例属性,无论它是否可枚举。

function Person(){
}
Person.prototype={
    constructor:Person,  //不这样设置,constructor将不指向Person,这样重设[[Enumerable]]特性被默认设置为true
    name:"name",
    age:29
}

重写整个原型对象,将切断现有原型与之前存在实例之间的联系。
通过原生对象的原型,不仅可以取得所有默认方法的引用,而且也可以定义新方法。
原型中所有属性被很多实例共享,默认情况下都将取得相同的属性值。但是实例没有属于自己的全部属性。
组合使用构造函数和原型模式,每个实例有自己的实例属性但又共享对方法的引用,最大限度节省了内存。是用来定义引用类型的一种默认模式。

function Person(name,age,job){
    this.name = name;
    this.job = job;
    this.age = age;
    this.friends = ["friend1","friend2"];
}
Person.prototype={
    constructor:Person,
    sayName:function(){
        alert(this.name);
    }
}
var person1 = new Person("Nicholas",29,"Engineer");
var person2 = new Person("Greg",27,"Doctor");
person1.frineds.push("Van");
alert(person1.friends); // friend1.friend2,Van
alert(person2.friends); // friend1.friend2

寄生构造函数模式,返回的对象与构造函数或者与构造函数的原型属性之间没有关系。使用instanceof操作符没有意义。

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;
}

稳妥构造函数模式
稳妥对象指没有公共属性,而且方法也不引用this的对象。最适合在一些安全的环境中(禁止使用this,new),或者在放在数据被其他应用改动时使用。

function Person(name,age,job){
    var o = new Object();
    var name1 =name;
    var age1 =age
    var job1 =job;
    o.sayName = function(){ 
        alert(name1);
    }
    return o;
}
var friend=Person("name",17,"worker");
friend.sayName(); //name
alert(friend.name); //undenfined

es中由于函数没有签名,无法实现接口继承,只支持实现继承,主要依靠原型链实现。
原型链基本思想是利用原型让一个引用类型继承另一个引用类型额属性和方法。

function SuperType(){
    this.property =true;
}
SuperType.prototype.getSuperValue =function(){
    return this.porpety;
};
function SubType(){
    this.subProperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue =  function(){
    return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());//true

原型链的所有引用类型默认都继承了Object。
使用字面量创建原型方法,会重写原型链。
原型链包含引用类型值的原型,被所有实例共享。不能在不影响所有对象实例的情况下,给超类型的构造函数传递参数。实践中很少单独使用原型链。
借用构造函数也叫伪造对象或经典继承。但函数无法复用,超类型的原型定义方法,子类型不可见。很少单独使用。

//借用构造函数
function SuperType(name){
    this.name = name;
}
function SubType(){
    SuperType.call(this,"name1"); //继承了SuperType,同时传递了参数。
    this.age =29;
}

组合继承也叫伪经典继承,既通过在原型上定义方法实现函数复用,又保证每个实例都有自己的属性。是最常用的继承方法。

function SuperType(name){
    this.name =name;
    this.colors = ['red','blue','green'];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
}
function SubType(name,age){
    //继承属性
    SuperType.call(this,name);
    this.age =aga;
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor =SubType;
SubType.prototype.sayAge =function(){
    alert(this.age);
}

原型式继承,对对象进行了浅复制。只想让一个对象与另一个对象保持类似,但包含引用类型的属性会共享相应的值。
object内部创建临时性的构造函数,传入对象作为构造函数的原型,返回临时类型的新实例。

var person ={
	name:'Nich',
	friends:['name1','name2','name3']
}
var anotherPerson = Object.create(person);
anotherPerson.name = 'Grey';
anotherPerson.friends.push('Rob');
alert(anotherPerson.name); //Grey
alert(anotherPerson.friends); //name1,name2,name3,Rob
alert(person.name); //Nich
alert(person.friends); //name1,name2,name3,Rob

var anotherPerson2 = Object.create(person,{name:{value:'gg'}});
alert(anotherPerson2.name);  //gg

寄生组合式继承,集寄生式继承和组合式继承的优点于一身,是实现基于类型继承的最有方式。

function inheritPrototype(suType,superType){
    var prototype = object(superType.protoType); //创建对象
    prototype.constructor = subType;//增强对象
    subType.prototype = prototype;//指定对象
}

你可能感兴趣的:(总结)