第八章 函数
闭包:function fun(){ var x = 0; } 外部是不能访问函数内部的局部变量的,因为函数一调用,局部变量就会被释放,这该怎么呢? 换个想法,因为 在函数内部 是能访问 外部的变量的, 于是乎: 在 函数 内部 再定义 一个函数,并使用该变量:
function f1(){
var x = 100; //局部变量
function f2(){
console.log(x++); //在函数内部再定义一个函数
}
return f2; //返回该函数
}
//调用,本来是 调用完 f1 就会销毁,但是现在 f2被赋给了全局变量 f,这导致f2一直在内存中,
//所以 f2不能被销毁,又因为 f2需要用到f1,所以f1也不能销毁。
var f = f1();
f(); //结果 100
f(); //结果 101
f(); //结果 102
//也就是说, 调用了 f1() 之后,x变量并没有被 回收!
关于闭包:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html (最后的思考题我还是答错了哈哈哈哈)
主要是两点:1,外部访问局部变量 2,保存到内存中,不会被释放。
//定义函数
function fun(){ ... }
var fun1 = function(){ ... }
var fun2 = function fun(){ ... }
//函数定义后可以直接执行
var value = (function(x){return x*x;}(10)); //结果100
//如果没有 return 语句,函数返回的是 undefined
//当方法不需要返回值时,最好返回this,这样就可以使用“方法链”:
shap.setX("x轴").setY("y轴")
//创建对象,没有形参的可以省略括号
var o = new Object();
var o = new Object;
function fun(a) {
if(a === undefined) a = [];
//可以写成如下形式:
//运算符 || ,第一个参数为真值得话就返回,否则返回第二个参数
a = a || [];
}
//callee 调用自身
var factorial = function(x){
if(x <= 1) return 1;
return x * arguments.callee(x-1);
};
//函数可以作为 对象的 属性
var o = { square: function(x){ return x*x;}};
var y = o.square(2); // 结果4
//甚至可以放到数组中
var a = [function(x){return x*x}, 2];
a[0](a[1]); //结果4
不在任何函数内声明的变量都是“全局变量”,在整个JavaScript程序中都是可见的,避免污染全局命名空间。
function mymodeule(){ //定义
}
mymodule(); //调用
//可以直接写个 匿名函数,并立即在单个表达式中调用它:
//注意这里的左括号是必须的,如此才不会将关键字function解析为函数声明语句,使用圆括号才会正确的将其解释为函数定义表达式
(function(){
}());
当 函数,含有嵌套函数时:
JavaScript函数的执行用到了“作用域链”,这个作用域链是“函数定义的时候创建的”。
闭包的特性: 它们可以捕捉到 局部变量/参数,并一直保存下来。
函数定义时的作用域链,函数执行时依然有效
function counter(){
var n = 0;
return {
count: function(){return n++;},
reset: function(){ n = 0; }
};
}
var c = counter();
c.count(); //0
c.count(); //1
c.reset(); //重置
c.count(); //0
c.count(); //1
利用闭包实现的私有属性取值方法:
function addpro(o,name,predicate){
var value;
o["get"+name] = function () {
return value;
};
o["set"+name] = function (v) {
if(predicate && !(predicate(v))){
throw Error("set"+name+": invalid value " + v);
}else{
value = v;
}
}
}
//调用
$(function () {
var o = {};
addpro(o,"Name",function (x) { return typeof x == "string"; });
o.setName("why_su");
console.log(o.getName()); //结果why_us
o.setName(0); //抛出异常 setName: invalid value 0
});
错误:
function fun1(){
var arrs = [];
for(var i = 0; i < 10; i++){
arrs[i] = function(){
return i;
}
}
return arrs;
}
//调用
var arrs = fun1();
console.log(arrs[5]()); //10,并不是5
//上面代码创建了 10个闭包,这些闭包都是在同一个函数调用中定义的,所以可以共享变量i,
//当fun1()返回时候,变量i的值是 10,所有的闭包都共享这一个值
8.8节看不懂。。。。
第九章 类
//构造函数
function Person(username){
this.username = username;
}
//构造函数加载完以后,会自动为构造函数生成一个对应的 原型对象
//Person构造函数有个属性prototype, 它指向的是 Person的原型对象
//也就是有两个对象, 一个是构造函数创建的对象,一个是原型对象
//将age, toString 保存在 原型对象中
Person.prototype.age = 24;
Person.prototype.toString = function () {
return "username:"+this.username+",age:"+this.age;
};
//创建的 实例, 指向了该原型对象。(也就是该构造函数所指向的原型对象)
var p1 = new Person("whysu");
var p2 = new Person("top");
console.log(p1.toString()); //username:whysu,age:24
console.log(p2.toString()); //username:top,age:24
//原型对象 有个属性 constructor 【反向指回】这个构造函数
console.log(Person.prototype.constructor); //结果 f Person(username){this.username=username;}
console.log(p1.constructor); //在p1实例上找不到constructor方法,就向该创建了该实例的构造函数所指向的原型查找有没有改方法,
//结果 f Person(username){this.username=username;}
看书看的头晕,找了篇视频,一点就通。。
两种写法的区别:
//这种写法是【覆盖,重置】原型对象
//因为原型对象默认会有一个属性constructor,如果这里不写的话,该属性就没有了
Person.prototype = {
constructor: Person, //需要显示设置构造函数反向引用
age: 24,
toString: function(){
return "username:"+this.username+",age:"+this.age;
}
}
//这种写法是在原有基础上【添加】,所以constructor没被覆盖
Person.prototype.age = 24;
Person.prototype.toString = function(){
return "username:"+this.username+",age:"+this.age;
}
构造函数初始化 后,js会自动为该构造函数 生成 原型对象, 那它是怎么生成的呢? 用的是:
Person.prototype = new Object(); 也就是生成了一个Object对象。
鸭式辩型:像鸭子一样走路、游泳并且嘎嘎叫的鸟就是鸭子。。
不要关注“对象的类是什么”,而是关注“对象能做什么”~
第9章看不懂。。。太多文字。。不理解。。
第10章 正则表达式
两种方式: var re = new RegExp("\d"); 或两个斜杠 var re = /\d/;
[ ... ] 方括号内任意字符 [^ ... ] 不在方括号内任意字符
. 任意字符(除了换行符)
\w 等价于[a-zA-Z0-9] \W 等价于 [^a-zA-Z0-9]
\d 等价于[0-9] \D 等价于 [^0-9]
\s 任意空白字符, \S 任意非空白字符
\b 代表着单词的开头或结尾,也就是单词的分界处,如果要搜寻 hi 这个单词的话,得用 \bhi\b,这样就不会搜寻类似him history这样的“包含”hi的单词
{n,m} 至少出现n次,最多m次 {n,} 出现n次 或多次 {n} 出现n次
? 0次或一次 + 一次或多次 * 0次或多次
^ 匹配字符串的开头,多行检索中匹配一行的开头
$ 匹配字符串的结尾,多行检索中匹配一行的结尾
贪婪的, 总是找最长的匹配的串
//得使用【行首 ^ 行尾 $ 】,/^ $/ 表示【所有匹配】而不是【部分匹配】
//例如:"-----123@qq.com---"也是【部分】符合的,但它不是合法的邮箱,
//必须使用 /^ $/ 表示【所有匹配】规则才行
var str4 = "123@qq.com";
var re = /^\w+@[a-z0-9]+\.[a-z]+$/i;
if(re.test(str4)){
alert("合法邮箱格式");
}else{
alert("邮箱格式不正确");
}
//将html标签过滤掉,获取纯文本
var str3 = "<h1>标题<span>666</span></h1><p>段落1</p>";
var re3 = /<.+>/g;
console.log(str3.replace(re3,"")); //结果 ""
//为什么会这样呢?因为正则有个特性【贪婪】,它会寻找匹配规则的【最长的】字符串,
//可以看见 <h1> </p> 左右< >是符合要求的
//于是整个字符串都被过滤了。所以需要<> 中不能出现<>
var re3_1 = /<[^<>]+>/g;
console.log(str3.replace(re3_1,"")); //结果 "标题666段落1"
//将字母a全部变为0
var str2 = "asdasd aaajoijio dsfa";
var re2 = /a/g;
alert(str2.replace(re2,0)); //结果0sd0sd 000joijio dsf0
//获得该字符串第一个数字
var str1 = "adsf 2 34 567 8910 csaddasd";
var re1 = /\d/; alert(str1.match(re1)); //结果 2
var re1_1 = /\d/g; alert(str1.match(re1_1)); //结果 2,3,4,5,6,7,8,9,1,0
var re1_2 = /\d{2}/g; alert(str1.match(re1_2)); //结果 34,56,89.10
var re1_3 = /\d+/g; alert(str1.match(re1_3)); //结果 2,34,567,8910
//第二个参数是option选项,i 表示忽略大小写
var re = new RegExp("a","i"); //等价于var re = /a/i; 在斜杆后面加 i
var str = "Abcdef";
console.log(str.search(re)); //结果 0
| 或者 ( ... ) 圆括号,分组,后面可以使用 \1 表示第1个分组,\3 表示第3个分组
(?: ...) 圆括号,也是分组,但不可以用 \1 、\3来表示
零宽断言,预搜索: 类似\b 只是规定【位置】要遵循的规则,但不返回这些结果
(?= exp) 后面要遵循的规则,
(?<=exp) 前面要遵循的规则
(?! exp) 后面不要遵循的规则
(?<! exp) 前面不要遵循的规则
“str”.search(/\d/i); 返回索引,找不到就返回-1 ,不支持全局搜索(会忽略修饰符 g)
"str".replace(/\d\gi,"a");
"str".match(/\d/g); 返回的是匹配的数组
"s-t-r".split("-"); 按 - 拆分
"str".exec(/\d/); exec和match方法一样是返回匹配数组,但exec返回的信息更加详细
第11章 JavaScript的子集和扩展
const 定义常量
const pi = 3.14; //定义常量
pi = 4; //任何对该常量【重新赋值】都会被忽略
const pi = 4; //重新声明常量会报错
var pi = 4; //报错
关键字 let 在 javascript1.7版本后才可用。
通过var 声明的变量在函数内部是可用的,而通过let声明的变量则只属于就近的花括号括起来的语句块。
解构赋值,索引对应的地方赋值
let [x,y] = [1,2]; //等价于 let x = 1,y = 2;
[x,y] = [y,x]; //交换两个变量的值
let [z,f] = [1]; // z = 1, y = undefined
[,x,,y] = [1,2,3,4]; //x = 2,y = 4;
11.4迭代,看的头晕,先跳过。。。