1. js 语言特性: 弱类型,不必声明变量类型。
3种原始类型:布尔型,数值型,字符串型;此外还有对象类型,函数类型,空类型(null)未定义类型(undefined)
原始类型按值传递,其他类型引用传递
javascript中模仿借口的三种方法: 注释法,属性检查法 和 鸭式辨型发
2. JavaScript构造类以及类的继承:
//****** Define the classA // 使用构造函数创建属性,prototype创建方法 // 原因: 1. 使用构造函数构建属性,实例化的每个对象就会有自己的属性,并且可以有初始化时参数 // 2. 而使用prototype构建方法的好处是,实例化的对象共享这个方法体,节省内存 function ClassA(id, age) { this.id = id; this.age = age; } /* 等同于上面使用构造函数的定义方法,这里使用的是匿名function定义类 var ClassA = function () { this.id = id; thia.age = age; } */ ClassA.prototype.sayId = function() {
constuctor: ClassA, alert(this.id); }; ClassA.prototype.sayAge = function () {
alert(this.age); } /* 等同于上面的定义方法的方式 ClassA.prototype = { sayId: function() { alert(this.id); }, sayAge: function() { alert(this.age); } } */
//****** Define the ClassB that inherit from ClassA 组合(构造函数+原型)继承 function ClassB(id, name) { ClassA.call(this, id); this.name =name; } ClassB.prototype = new ClassA();
ClassB.prototype.constructor = ClassB; ClassB.prototype.sayName=function(){ alert(this.name); } var b = new ClassB(222, "nemo"); console.log(b.id); console.log(b.name); b.sayId();
// 字面量方式来定义类
function Person() {
}
Person.prototype = {
constructor: Person, name: "default name", getName: function () { return this.name; } }; // 原型式继承 var reader = clone(Person); function clone(object) { // 这里相当于定义一个子类的构造函数 function F () {}; // 把传进来的父类参数作为子类的prototype属性 F.prototype = object; // 最后new创建出一个新的对象 并返回 return new F; }
// clone 出来的所有子类都共享父类对象的每个属性和方法的唯一一份实例,因此相比类式继承 更节省内存空间
// 同时需要注意:对继承而来的成员的读和写的不对等性:读取时是读取原型的属性,儿写属性时则是为实例新创建一个属性并覆盖了同名的原型属性
alert(reader.name);
说明:
当执行 var person1 = new ClassA() 时所实际发生的事情:这里定义的ClassA 实质上只是一个function对象,C大写也只是约定。因此他和别的函数没有本质区别,而和其他功能性函数的重要区别在于函数内部定义的方式(使用了this关键字来定义域的变量,表示这些变量属于所定义的这个函数)以及调用方式(使用new来调用)。当使用new关键字来初始化这种定义方式的function时:
1) 因为使用的new关键字,因此这时创建一个新对象
2) 将函数的作用域赋给新对象,因此this就指向这个新对象
3) 执行函数中的代码,这时为对象添加属性
4) 返回new关键字定义的对象
======================================================================================================
原型,构造函数,实例之间的关系:
创建的每个函数(当然包含构造函数)都有一个原型属性,原型属性是一个对象,即prototype是一个对象。原型对象包含了构造函数所定义的所有属性和方法。
除此之外prototype默认会创建一个constructor属性,这个属性是对构造函数的一个引用,即又指向了构造函数。因此构造函数 和 其prototype之间是双向引用的关系。
而由构造函数创建的实例都包含一个__proto__属性,这个属性指向构造函数的prototype属性对象,因此每个实例才都共享同一个prototype这个对象。而实例和构造函数没有直接关系,是和构造函数的prototype直接相关。
3. JS闭包:
当在一个函数 outter 内部定义另一个函数 inner,而 inner 又引用了 outter 作用域内的变量,在 outter 之外使用 inner 函数,则形成了闭包。描述起来虽然比较复杂,在实际编程中却经常无意的使用了闭包特性。
function foo () { var a = 10; function bar () { a = a * 2; return a; } return bar; } var baz = foo(); baz(); // return 20. baz(); // return 40. baz(); // return 80. var bult = foo(); bult(); // return 20;
函数式运行在定义它们的作用域中(foo内部的作用域),而不是运行在调用它们的作用域中。只要bar被定义在foo中,它就能访问在foo中定义的的所有变量,即使foo的执行已经结束。
在foo返回后,它的作用域被保存下来,但只有它返回的那个函数能够访问这个作用域。即只有bar能访问这个作用域。
4. 用闭包实现私有成员:
var Book = function (id, name) { // private attributes 定义私有变量/属性,这里定义的时候没有使用this关键字,表明只存在于Book构造器中 var id, name; // private method function checkId () { ... } // Privileged methods 定义私有变量的get,set方法,这里形成闭包,即针对一个book的实例,只有这个实例的getId这个方法能访问book内的id变量, this.getId = function() { return id; } this.setId = function(newId) { if (!checkId(newId)) throw new Error ('Book: Invalid Id'); id = newId; } this.getName = function () { return name; } this.setName = function(newName) { name = newName; } // Constructor code 调用上面的get,set方法来完成构造函数的私有变量初始化工作 this.setId(id); this.setName(name); }; // public method, non-privileged method 在prototype里定义公有方法,公有方法需要访问私有属性的时候 就可以调用上面定义的get,set方法 Book.prototype = { display: function () { ... } ... }
5. JS的作用域工作原理:
第一步:创建: 首先在js中方法也是一个对象,因此方法也可以有自己的属性。当方法被创建时,他的一个内部属性(仅供js引擎使用) [[scope]]被创建, 这个[[scope]]又包含一个属性叫作用域链,他包含创建这个函数的作用域中所有对象的集合( eg:如果这个函数是在全局中创建的,那作用域链中就包含:window, document, 以及定义在全局中的变量 )。我觉得这里可以忽略[[scope]] 这个属性,而记住函数在创建的时候,会随之创建与他相关的作用域链。
第二步:运行: 当运行这个方法时,会创建另一个内部对象叫运行期上下文。一个运行期上下文定义函数运行时的环境。运行期上下文有自己的作用域链,里面包含两个对象,第一个叫“激活对象”,包含访问所有局部变量,命令参数,参数集合,和this的接口。第二个是之前定义函数时创建的作用域链。
因此,在函数运行的过程中,每遇到一个变量,为了获取其值都会从运行期上下文的作用域链中从上到下进行搜索。即先从“激活对象”(局部变量, 命令参数...)中找。如果找不到,再到定义函数时的创建的作用域链中找。如果始终找不到,则被认定为未定义。
这样就可以理解:闭包中内层函数可以读取外层函数内定义的变量。
与此相关的优化工作:因为读取局部变量 比 读取创建作用域链中的变量(在更深层次中查找) 的性能开销大,因此在函数多于一次使用本地范围之外的变量值时,可以考虑先定义一个本地变量来引用这个外地变量,之后使用这个定义的本地变量。这样只需要查找一次,节省开销。简单的说,引入局部变量,消除搜索深度搜索过程。
6. JS中的原型prototype
JavaScript中的对象是基于原型的。原型是其他对象的基础,定义并实现了一个新对象所必须具有的成员。原型对象为所有给定类型的对象实例所共享,因此所有实例共享原型对象的成员。
每个对象的实例包含两种类型的成员: 实例成员(自己定义的成员),原型成员(从对象原型中继承的成员)
可以用hasOwnProperty() 来判断一个对象是否具有特定名称的"实例成员"。 eg:book.hasOwnProperty("title");
可以用in来判读对象是否具有某个名称的属性. eg: "title" in book;
7. 原型链:P49
8. 静态方法和属性:
9. DOM性能:轻轻的触摸DOM,并尽量保持在ECMAScript中。

浙公网安备 33010602011771号