javascript 深入浅出 (未完成4-17)
慕课网javascript总结 课程地址
课程大纲:
一、数据类型 二、表达式和运算符 三、语句 四、对象 五、数组 六、函数 七、this 八、闭包和作用域 九、OOP 十、正则与模式匹配
------------------ 正文部分开始-----------------------
一、数据类型
六种类型:
5种基本类型(String,Number,Boolean,Undefined,Null)+Object( Array,Date,RegExp,Function (从技术角度上来说,函数在ECMAScript中是对象,不是一种数据类型),基本包装类型,单体内置类型 )
类型检测:
1.typeof 返回字符串,适合基本类型(除了null, typeof null //Object)及函数检测 ( typeof (function(){}) // function typeof [,,] // Object typeof (new Date()) // Object typeof {}// Object )
2.instanceof 返回布尔值,基于原型链来检测(原理: a instanceof b,看是否b(构造函数)的prototype属性在a的原型链上 ),适合对象检测(可以区分数组,日期等)适合自定义对象,也可以用来检测原生对象,在不同iframe和window间检测时失效。
3.Object.prototype.toString JavaScript:Object.prototype.toString方法的原理
Object.prototype.toString.apply([]); === “[object Array]”;
Object.prototype.toString.apply(function(){}); === “[object Function]”;
Object.prototype.toString.apply(null); === “[object Null]”
Object.prototype.toString.apply(undefined); === “[object Undefined]”
4.constructor
5.duck type
二、表达式和运算符
表达式:
原始表达式 1. 常量、直接量 eg: 3.14 "string" 2. 关键字 eg: null this true
初始化表达式
函数表达式
属性访问表达式 eg: obj.x 或 obj.[x]
调用表达式 func()
对象创建表达式 eg: new Func(1,2) 或 new Object
运算符:
一元
三、语句
Javascript程序由语句组成,语句遵守特定的语法规则。
block break continue empty if...else switch try catch
var function return do...while for for...in while
debugger label with
block: 块语句用一对花括号定义,但是javascript中没有块级作用域。 for循环中,var i 在花括号内和在花括号外声明效果相同。
function: 函数声明提升
for...in : 1. 顺序不确定 2. enumerable为false时不会出现 3. for in对象属性时受原型链影响
四、对象
ECMA-2把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”严格来说,这就相当于说对象是一组没有特定顺序的值。对象的属性或方法都有一个名字,而每个名字映射到一个值。我们可以把ECMAScript的对象想象成散列表,无非就是一组名值对,其中值可以是数据或函数。(高程三 P139)
1. 创建对象
1.1 通过 Object()
使用Object构造函数来创建一个对象,即创建一个Object的实例,俗话说的new一个实例。
var person = new Object(); person.name="kevin"; person.age=31; person.sayName = function(){ alert(this.name); }
1.2 通过字面量
var person = { name:"Kevin", age:31, 5:"Test" }; alert(person.name); alert(person["5"]);
1.3 工厂模式
function createPerson(name, age,job) { var o = new Object(); o.name=name; o.age=31; o.sayName=function() { alert(this.name); }; return o; // 返回实例 } createPerson("kevin",31,"se").sayName();
原理就是定义一个工厂函数,函数内部创建一个Object实例,然后向实例添加属性与方法,最后返回这个实例。
这个模式解决了创建相似对象的问题,缺点没有对象识别的功能(即怎样知道一个对象的类型)。
1.4 构造函数
1 function Person(name,age,job) 2 { 3 this.name=name; 4 this.age=age; 5 this.job=job; 6 this.sayName=function() // 虽然每个对象拥有同名的方法,但其实每个对象实例的方法都是不同的Function实例。我们可以将this.sayName = function(){…}想象成this.sayName = new Function(“…”),这两个表达式逻辑上是等价的。 7 { // 如果需要多个实例,则创建完成同样任务的多个Function实例是没有必要的 (高程三 P147) 8 alert(this.name); // 9 }; 10 } 11 12 var person = new Person("kevin",31,"SE"); 13 person.sayName();
使用自定义构造函数模式创建对象。与工厂模式相比的优点,构造函数模式,没有显示创建Object实例,而且可以标识对象类型(可以找到实例的原型)。
定义构造函数注意的地方是: 函数名首字母大写; 实例化对象时要用new操作符;以这种方式调用构造函数,实际运行4个步骤:
- 创建一个新对象;
- 将构造函数作用域赋予新对象(因此this指向新对象);
- 执行构造函数中的代码(为新对象添加属性);
- 返回新对象;
构造函数的改进版:
1 function Person(name,age,job) 2 { 3 this.name=name; 4 this.age=age; 5 this.job=job; 6 this.sayName=sayName; //将sayName()函数的定义转移到了构造函数的外部 7 } // sayName 包含的是一个指向sayName() 的指针 8 function sayName(){ // 因此,实例对象就共享了在全局作用域中定义的同一个函数sayName() 9 alert(this.name); 10 }
缺点是:
作用域
如果对象需要多个方法,则需要多个全局函数,于是自定义的引用类型就丝毫没有封装型可言了。
1.5 原型模式
我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
prototype是通过调用构造函数而创建的那个对象实例的对象原型,使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。
1 function Father(){}; 2 Father.prototype.name = "hhhhh"; // 原型对象上 有 两个属性 和 一个方法, 3 Father.prototype.lastname = "wwwwww"; // 很自然,会想到要把他们合并到一个对象里面 4 Father.prototype.sayName = function(){}; // 就有了下面的 简写 的原型模式 5 var obj1 = new Father(); 6 obj1.name // hhhhh
原型简写方式
1 function Father(){}; 2 Father.prototype = { // 与 字面量 声明对象 类似 3 name:"hhhhh", // 因此,原型对象 的 构造函数 指向了 Object() 4 lastname:"wwwww", 5 sayName:function(){ 6 } 7 } 8 var obj1 = new Father(); 9 console.log(obj1 instanceof Father); // true 10 console.log(Father.prototype.constructor); // Object() { [native code] } 11 console.log(obj1.constructor); // Object() { [native code] }
如果constructor很重要,则需要特意将其设为适当的值.
即在对象原型中添加属性
constructor:Father; // 重新指向构造函数
原型的动态性
由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反映出来。
如果重写整个原型对象,情况就不一样了。调用构造函数时会为实例添加一个指向最初原型的[[prototype]]指针,而把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。实例中的指针仅指向原型,而不指向构造函数。
1 function Father(){}; 2 var obj1 = new Father(); // 原型链已经构成 3 Father.prototype = { // 字面量方式,则原型对象被改写 4 name:"hhhhh", 5 lastname:"wwwww", 6 sayName:function(){ 7 } 8 }
function Person() { } Person.prototype = { // constructor : Person, name:"kevin", age:31, job:"SE", friends:["Jams","Martin"], sayFriends:function() { alert(this.friends); } }; var person1 = new Person(); person1.friends.push("Joe"); // 实例person1和person2访问的是同一组属性和同一个sayName()函数 person1.sayFriends();//Jams,Martin,Joe var person2 = new Person(); person2.sayFriends();//James,Martin,Joe
问题所在: (高程三 P158)
1. 所有实例默认情况下都将取得相同的属性值
2. 对于包含引用类型的属性值来说,问题很突出。 person1.friends和person2.friends指向的是同一个数组(在Person.prototype中,因此会造成互相影响)
1.6 组合使用原型模式和构造函数创建对象
1 function Person(name,age,job) // 构造函数部分 用于定义 实例 的属性 2 { 3 this.name=name; 4 this.age=age; 5 this.job=job; 6 this.friends=["Jams","Martin"]; 7 } 8 Person.prototype.sayFriends=function() // 原型部分 用于定义 方法 和 共享 的 属性 9 { 10 alert(this.friends); 11 }; 12 var person1 = new Person("kevin",31,"SE"); 13 var person2 = new Person("Tom",30,"SE"); 14 person1.friends.push("Joe"); 15 person1.sayFriends();//Jams,Martin,Joe 16 person2.sayFriends();//Jams,Martin
1.7 动态原型模式
1 function Person(name,age,job) 2 { 3 //属性 4 this.name=name; 5 this.age=age; 6 this.job=job; 7 this.friends=["Jams","Martin"]; 8 //方法 9 if(typeof this.sayName !="function") // 这段代码只有在初次调用时候才会执行 10 { 11 Person.prototype.sayName=function() 12 { 13 alert(this.name); 14 }; 15 16 Person.prototype.sayFriends=function() 17 { 18 alert(this.friends); 19 }; 20 } 21 } 22 23 var person = new Person("kevin",31,"SE"); 24 person.sayName(); 25 person.sayFriends(); 26 复制代码
1.8 寄生构造函数模式和稳妥构造函数模式
2. 属性检测
五、数组
六、函数
七、this
八、闭包和作用域
闭包:指有权访问另一个函数作用域中的变量的函数。(《高程三》P178 注意断句)
九、OOP
十、正则与模式匹配
http://www.imooc.com/comment/277