81、函数内部属性:arguments、arguments.callee、this。
window.color = "red";
var o={color:"blue"};
function sayColor()
{
alert(this.color);
}
sayColor(); // red
o.sayColor = sayColor;
o.sayColor(); // blue
函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的sayColor()函数与o.sayColor指向的是同一个函数。
82、caller:保存着调用当前函数的函数的引用。
83、函数的属性,方法。函数都包含两个属性:length和prototype。
length:表示希望接收命名参数的个数。
prototype:是保存它们所有实例方法的真正所在。
prototype属性不可枚举,fot-in 无法发现。
84、每个函数都包括两个非继承而来的方法:apply()和call()。在特定作用域中调用函数。作用相同,区别在接收函数的参数的方式不同。
function sum(num1, num2)
{
return num1+num2;
}
function callSum1(num1,num2)
{
return sum.apply(this, arguments); //this因为在全局在调用,调用的window
}
function callSum2(num1,num2)
{
return sum.apply(this,[num1,num2]);
}
alert(callSum1(10,10)); //
alert(callSum2(10,10)); //
function callSum(num1,num2)
{
return sum.call(this,num1,num2);
}
alert(callSum(10,10)); //
85、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
86、使用call() 和 apply()来扩充作用域的最大好处,就是对象不需要与方法有任何耦合。
87、bind():创建一个函数实例,其this值会被绑定到传给bind()函数的值。
window.color = 'red';
var o = {color:'blue'};
function sayColor()
{
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); // blue
基本包装类
88、引用类型和基本类型的区别: 生存周期
使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中,
自动创建的基本类型的对象,在存在于一行代码执行的瞬间。
var s1 = "some text";
s1.color = "red";
alert(s1.color); // undefined
Boolean类型
89、
Number类型
90、与boolean类型和string等所有基本类型一样,
重新了valueOf、toLocaleString、toString方法。
重写后valueOf返回基本类型的数组。
Number类型提供了一些将数值转化为字符串的方法toFixed。
String类型
91、length、charAt和charCodeAt:都接受一个参数,基于0字符的位置。concat:将一个火多个字符拼接起来。
92、slice、substring、substr、slice、substring、substr
var stringValue = 'hello world';
alert(stringValue.slice(3)); // lo world
alert(stringValue.substring(3)); // lo world
alert(stringValue.substr(3)); // lo world
alert(stringValue.slice(3,7)) // lo w
alert(stringValue.substring(3,7)) // lo w
alert(stringValue.substr(3,7)) // lo worl
93、indexOf, lastIndexOf, trim
94、toLowerCase、toLocaleLowerCase、toUpperCase、toLocaleUpperCase、大小写转换方法。
95、字符串模式匹配方法。match:只接受一个参数,要么是一个正则表达式,要么是RegExp对象。返回一个数组。
- sharch:查找。
- replace:替换。
- split:字符串分割。
- localeCompare:字符串比较方法。
Global和Math对象
96、不依赖宿主环境的单体内置对象:Global和Math对象。
97、Global对象:isNaN、isFinite、parseInt、parseFloat。
98、url编码方法:encodeURI和encodeURIComponent对URI进行编码。decodeURI和decodeURIComponent解码。
99、eval:就像一个ECMA解析器。(小心代码注入)。
100、Global的属性:undefined、Nan、等,所有原生态引用类型:Object、Functon、Global等对象都是Global的属性。
101、window对象:大多情况ECMA不能直接访问Global对象,Web浏览器实现了承担该角色的window对象。
102、Math对象:min和max方法。ceil、floor、round、方法。random:随机数。
面向对象
103、ECMA中的函数就是对象,每定义了一个函数就实例化了一个对象。
104、
105、构造函数:构造函数和函数的区别就是调用他们的方式不同,构造函数也是函数,任何函数,只有通过new操作符来调用,它就可以作为构造函数。任何不同通过new来调用的函数就是普通函数。this对象总是指向Global对象(浏览器的window对象)。
106、构造函数的问题:每个方法都要在实例是重新创建一遍。
理解对象
//对象1
var person = new Object();
person.name = 'Nicholas';
person.age = 29;
person.job = "Software Engineer";
person.sayName = function()
{
aerlt(this.name);
}
//对象2
var person = {
name:“Nicholas”;
age:29;
job:"Software Engineer";
sayName : function()
{
alert(this.name);
}
}
属性类型
107、ECMA两种属性:数据属性和访问属性。数据属性有4个描述其行为的特性:
1、Configurable:通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。能直接在对象上定义属性特性的它的默认值是true。
2、Enumerable:表示能否通过for-in循环返回属性。直接在对象定义的属性他们的默认值是true。
3、Writable:表示能否修改属性的值。直接在对象定义的属性他们的默认值是true。
4、Value:包含这个属性的数据值。读取属性的时候,从这个位置读,写入属性值的时候,在新值保存在这个位置。默认值是:undefined。
5、要修改属性ECMA5的Object.defineProperty()方法。接收三个参数:属性所在的对象、属性的名字和一个描述符对象。描述符对象的属性是:configurable、enumerable、writable 和value。设置其中的一或者多个值。
var person={};
Object.defineProperty(person, "name",{
writable:false,
value:"Nicholas"
});
alert(person.name);
//Nicholas;
person.name = "Greg";
alert(person.name);
//Nicholas;
应该name的属性是只读,所以修改不了。
访问器属性
108、访问器属性不包含数据值;它们包含一对儿getter和setter函数。在读取访问器属性时,调用getter函数,负责返回有效的值;写入访问器属性时:会调用setter函数传入新值,负责决定如何处理数据。
Configurable:表示能否通过delete删除属性从而重新定义属性。对直接在对象上定义的属性的默认值是true。
Enumerable:表示能否通过for-in返回属性。直接在对象上定义的属性默认值是true。
Get:在读取属性时调用的函数:默认值:undefined。
Set:在写入属性时调用的函数:默认值:undefined。
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 = 2005;
alert(book.edition); //
定义多个属性:Object.definePro-Perties()。
构造函数模式
110、new创建实例的步骤:1、创建一个新对象。2、将构造函数的作用域给新对象(因此this就指向了这个新对象);3、执行构造函数中的代码(为这个新对象添加属性)4、返回新对象。
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
alert(this.name);
};
} var person1 = new Person('nic', 29, 'So');
var person2 = new Person('gre', 27, 'Doct');
// person的构建造函数是Person
alert(person1.constructor == Person);
alert(person2.constructor == Person);
//检测person的对象类型
alert( person1 instanceof Object);
//true
alert( person1 instanceof Person);
//true
111、构造函数模式缺点:每个方法都有在每个实例上重新创建一遍。解决方案是原型模式。
原型模式
107、原型模式:每个函数都有一个prototype原型属性,这个属性是一个指针,指向一个对象。prototype就是通过调用构造函数而创建的那个对象实例的原型对象。
108、原型的好处:可以让所有的对象实例共享它所包含的属性和方法。不必在构造函数中定义对象实例的信息,而是将这些信息直接添加到原型对象中。
109、理解原型对象:firefox、chrome访问原型__proto__。当调用一个构造函数创建一个新实例后,实例的内部包含一个指针,指向构造函数的原型对象。这个指针就是prototype。这个链接存在于实例与构造函数的原型对象之间。不是存在于实例与构造函数之间。
function Person() {
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function() {
alert(this.name);
};
var person1 = new Person();
person1.sayName();
// Nicholas var person2 = new Person(); person2.sayName();// Nicholas
// person1 与 person 继承了都继承了原型的sayName方法
alert(person1.sayName === person1.sayName);
//true
//person1、person是两个独立的对象,它们有相同的原型。ecma中函数也是对象。
alert(person1.__proto__ == person2.__proto__);
// true
//
alert(Person.__proto__);
//函数的原型是一个函数体
//
alert(person1.__proto__);
//原型是一个对象。
//
alert(Person.prototype.isPrototypeOf(person1));
//true
alert(Person.prototype.isPrototypeOf(person2));
//true
//它们内部都有一个指向Person.prototype的指针。
110、ECMA5中Object.getPrototypeOf(),返回的对象实际就是这个对象的原型。
111、ECMA5的Object.getOwnPropertyDescriptor()方法只能用于实例属性,要取得原型属性的描述符,必须直接在原型对象上调用Object.getOwnProperty-Descriptor()方法。
原型与in操作符
112、in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中。
function Person() {
};
//
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
//
Person.prototype.sayName = function() {
alert(this.name);
};
//
var person1 = new Person();
var person2 = new Person();
//
alert(person1.hasOwnProperty("name"));
// false
alert("name" in person1);
// true
//
person1.name = "Greg";
alert(person1.name);// Greg -- 来自实例
alert(person1.hasOwnProperty("name"));// true
alert("name" in person1);// true
//
alert(person2.name);// Nicholas --来自原型
alert(person2.hasOwnProperty("name"));// false
alert("name" in person2);//true
//
delete person1.name;
alert(person1.name);
//Nicholas -- 来自原型
alert(person1.hasOwnProperty("name"));
// false
alert("name" in person1);
//true
113、hasPrototypeProperty()的用法。 ( 火狐中没有这个函数)
function Person(){}; // Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; // Person.prototype.sayName = function() { alert(this.name); }; var person1 = new Person(); alert(hasPrototypeProperty(person1,"name")); //true -- 来自原型 person.name = "Greg"; alert(hasPrototypeProperty(person1,"name")); //false --来自对象
114、Object.keys():参数一个对象,返回所以可枚举属性的字符串数组。如果你要得到所有实例属性,无论它是否可以枚举,都可以使用
function Person() {
};
Person.prototype.name = 'ni';
Person.prototype.age = 19;
Person.prototype.job = 'Software';
Person.prototype.sayName = function() {
alert(this.name);
};
//
var keys = Object.keys(Person.prototype);
//枚举实例的属性
alert(keys);//name,age,job,sayName
//
var p1 = new Person();
p1.name = 'ROB';
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys);//"name,age"
var keys = Object.getOwnPropertyNames(Person.prototype);// 枚举实例所以得属性,包括不可见的
alert(keys);// constructor,name,age,job,sayName
更简单的原型语
function Person() {
};
Person.prototype = {
name : "Nicholas",
age : 29,
job : "Software Engineer",
sayName : function() {
alert(this.name);
}
};
var friend = new Person();
alert( friend instanceof Object);//true
alert( friend instanceof Person);//true
alert(friend.constructor == Person);//false
alert(friend.constructor == Object);//true
//
原型的动态性
//
原生对象的原型
//
原型对象的问题
//
组合使用构造函数模式和原型模式
//
继承
//
闭包
http://hi.baidu.com/fmyppjcxknfpvyr/item/d14e951e94bc5efd9d778a5e
定义:
1、闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。
2、闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。(这个不是官方定义,但是这个定义应该更有利于你理解闭包)
3、当在一个函数内定义另外一个函数就会产生闭包。
理解:
做为局部变量都可以被函数内的代码访问,这个和静态语言是没有差别。闭包的差别在于局部变变量可以在函数执行结束后仍然被函数外的代码访问。这意味着函数必须返回一个指向闭包的“引用”,或将这个”引用”赋值给某个外部变量,才能保证闭包中局部变量被外部代码访问。当然包含这个引用的实体应该是一个对象,因为在Javascript中除了基本类型剩下的就都是对象了。可惜的是,ECMAScript并没有提供相关的成员和方法来访问闭包中的局部变量。但是在ECMAScript中,函数对象中定义的内部函数(inner function)是可以直接访问外部函数的局部变量,通过这种机制,我们就可以以如下的方式完成对闭包的访问了。
function greeting(name) {
var text = 'Hello ' + name;
// local variable
// 每次调用时,产生闭包,并返回内部函数对象给调用者
return function() {
alert(text);
};
} var sayHello = greeting("Closure");
sayHello(); // 通过闭包访问到了局部变量text
上述代码的执行结果是:Hello Closure,因为sayHello()函数在greeting函数执行完毕后,仍然可以访问到了定义在其之内的局部变量text。
好了,这个就是传说中闭包的效果,闭包在Javascript中有多种应用场景和模式,比如Singleton,Power Constructor等这些Javascript模式都离不开对闭包的使用.
//
用处:一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
function f1(){
var n=999;
function f2(){
alert(n);
};
return f2;
}
var result=f1();
result(); //
function f1(){
var n=999;
nAdd=function(){n+=1};
function f2(){ alert(n);};
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); //
var name = "The Window";
var object = {name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()); //function(){retturn this.name}
alert(this.name); // the window
alert(object.getNameFunc()()); //the window
this对象
115、this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window。而当函数被作为某个对象的方法调用是,this等于那个对象。
匿名函数的执行环境具有全局性。因此this对象通常指向window。
var name = 'the wiondw';
var object = {
name : 'My Object',
getName : function() {
return this.name;
}
};
alert(object.getName());//my object
alert((object.getName)()); //my object alert(object.getName);
alert((object.getName = object.getName)()); // this window //先执行一条赋值语句,然后再调用赋值后的结果。因为这个赋值表达式的值是函数本身,所以this的值不能得到维持。
块级作用域
116、for中变量i的定义是在函数内,for结束,i不会被销毁。域名函数可以来避免这个问题。
//问题 function outputNumbers(count) { for(var i=0; i<count; i++) { // alert(i); } alert(i);//计数 } outputNumbers(2); //2 // 解决方法 function outputNumbera(count) { (function() { for(var s=0; s<count; s++) { // alert(i); } })(); alert(s);//计数 } outputNumbera(2); //2
这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用域链。