1. 函数的定义和使用
- 所有的函数都是 Function的实例对象
- 函数也属于对象
函数内this指向,更全面版
// 1. 普通函数 this 指向window
function fn() {
console.log('普通函数的this' + this);
}
window.fn();
// 2. 对象的方法 this指向的是对象 o
var o = {
sayHi: function() {
console.log('对象方法的this:' + this);
}
}
o.sayHi();
// 3. 构造函数 this 指向 ldh 这个实例对象 原型对象里面的this 指向的也是 ldh这个实例对象
function Star() {};
Star.prototype.sing = function() {
}
var ldh = new Star();
// 4. 绑定事件函数 this 指向的是函数的调用者 btn这个按钮对象
var btn = document.querySelector('button');
btn.onclick = function() {
console.log('绑定时间函数的this:' + this);
};
// 5. 定时器函数 this 指向的也是window
window.setTimeout(function() {
console.log('定时器的this:' + this);
}, 1000);
// 6. 立即执行函数 this还是指向window
(function() {
console.log('立即执行函数的this' + this);
})();
apply函数
- 也是调用函数,可以改变函数内部的this指向
- 参数必须是数组
- apply参数中的数组在函数中类似解构,可以和Math对象联合使用
var arr = [1, 66, 3, 99, 4];
var max = Math.max.apply(Math, arr);
var min = Math.min.apply(Math, arr);
console.log(max, min); // => 99 1
bind函数(捆绑函数)
- 不会调用原来的函数,可以改变原来函数内部的this指向
- 返回的是原函数改变this后产生的新函数
var o = {
name: 'andy'
};
function fn(a, b) {
console.log(this);
console.log(a + b);
};
var f = fn.bind(o, 1, 2);
f(); // => o 3
- bind可以和定时器联动使用,解决this指向问题
- 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时用bind
var btn1 = document.querySelector('button');
btn1.onclick = function() {
this.disabled = true; // 这个this 指向的是 btn 这个按钮
// var that = this;
setTimeout(function() {
// that.disabled = false; // 定时器函数里面的this 指向的是window
this.disabled = false; // 此时定时器函数里面的this 指向的是btn
}.bind(this), 3000); // 这个this 指向的是btn 这个对象
}
var btns = document.querySelectorAll('button');
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
this.disabled = true;
setTimeout(function() {
this.disabled = false;
// btns[i].disable = false; 不可用,for立即执行,当定时器执行此语句时i一直是4,越界
}.bind(this), 2000);
}
}
// 这样的好处就是bind立即执行,和for循环速度一致,但是又不会立即调用定时器里面的函数,而且代码简洁,
严格模式
为脚本实现严格模式
<script>
'use strict';
</script>
为函数实现严格模式
function fn() {
'use strict';
}
严格模式作用
- 变量需要先声明再使用
- 不可以删除声明好的变量
- 全局作用域中函数的this(函数内打印this)不再指向window而是undefined
高阶函数
- 接收函数作为参数(比如回调函数),将函数作为返回值输出都叫做高阶函数(比如闭包)
闭包
- 闭包指有权访问另一个函数作用域中变量的函数(变量所在的函数就是闭包函数)
- 一个作用域可以访问另一个函数的局部变量
- 闭包的主要作用:延伸了变量的作用范围
// 给所有小li添加点击事件:打印索引
// 利用for循环创建4个立即执行函数
// 立即执行函数也叫做小闭包,因为立即执行函数里面的任何一个函数都可以使用i变量
// 但是用这种方法就开销大,因为立即执行函数里面i一直要存在供调用,没办法释放立即执行函数
for(var i = 0; i < lis.length; i++){
(function(i){
lis[i].onclick = function(){
console.log(i);
}
})(i);
}
打车案例
// 闭包应用-计算打车价格
// 打车起步价13(3公里内), 之后每多一公里增加 5块钱. 用户输入公里数就可以计算打车价格
// 如果有拥堵情况,总价格多收取10块钱拥堵费
var car = (function () {
var start = 13;
var total = 0;
return {
price: function (n) {
if(n <= 3){
total = start;
} else {
total = start + (n - 3) * 5;
}
return total;
},
yd: function(flag){
flag? total += 10: total += 0;
return total;
}
}
})()
console.log(car.price(5)); // => 23
console.log(car.yd(true)); // => 33
console.log(car.price(2)); // => 13
关于闭包的思考
// 思考题 1:
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
return function() {
return this.name;
};
}
};
console.log(object.getNameFunc()()) // => 'The Window'
// 类似于
var f = object.getNameFunc();
var f = function() {
return this.name;
// 匿名函数的执行环境具有全局性,所以其this对象通常指向window。(原话)
}
f();
// 思考题 2:
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
var that = this;
return function() {
return that.name;
};
}
};
console.log(object.getNameFunc()()) // => 'My Object'
浅拷贝与深拷贝
浅拷贝
-
浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用
-
浅拷贝1
var obj = {
id: 1,
name: 'andy',
msg: {
age:18
}
};
var o = {};
for(var k in obj){
o[k] = obj[k]
}
console.log(o); // msg: {age: 20}
o.msg.age = 20;
console.log(obj); // msg: {age: 20}
- 浅拷贝2
var obj = {
id: 1,
name: 'andy',
msg: {
age:18
}
};
var o = {};
Object.assign(o, obj);
console.log(o); // msg: {age: 20}
o.msg.age = 20;
console.log(obj); // msg: {age: 20}
深拷贝
- 深拷贝拷贝多层,每一层数据都会拷贝
- 深拷贝1
var obj = {
id: 1,
name: 'andy',
msg: {
age:18
}
};
var o = {};
function deepCopy(newObj, oldObj){
for(var k in oldObj){
var item = oldObj[k];
if(item instanceof Array){
newObj[k] = [];
deepCopy(newObj[k], item)
} else if(item instanceof Object) {
newObj[k] = {};
deepCopy(newObj[k], item)
} else {
newObj[k] = item
}
}
}
deepCopy(o, obj);
console.log(o); // msg: {age: 20}
o.msg.age = 20;
console.log(obj); // msg: {age: 18}
2. 正则表达式
- 正则表达式是用于匹配字符串中字符组合的模式,在js中是对象
创建
- 用对象来创建正则表达式
var regexp = new RegExp(/123/);
- 字面量
var rg = /123/;
测试
console.log(rg.test(123)); // => true
console.log(rg.test('abc')); // => false
边界符
- 正则表达式里面不需要加引号,不管是数字还是字符串
- ^开头 $结尾
var rg = /abc/;
console.log(rg.test('abc')); // => true 只要字符串中包含abc字符串就true
var reg = /^abc/; //要以abc开头才行
var reg1 = /abc$/; // 要以abc结尾
var reg2 = /^abc$/; //只匹配abc abcabc都不行
字符类
var rg = /[abc]/; //只要出现a或b或c就true
var rg = /^[abc]$/; //只能是一个a或b或c字母,aa不可,abc不可,a可
// [-] 中括号加个-表示范围
var reg = /^[a-z]$/; //26个字母随便一个且仅一个
var reg = /^[a-zA-Z0-9_-]$/; //从多个里面选一个就可以了,字母,数字, _, -都可以
// 中括号里面有^表示取反
/^[^abc]$/.test('a') // => false
量词符
量词符: 用来设定某个模式出现的次数
// * 相当于 >= 0 可以出现0次或者很多次
var reg = /^a*$/;
console.log(reg.test(''));
console.log(reg.test('a'));
console.log(reg.test('aaaa'));
// + 相当于 >= 1 可以出现1次或者很多次
var reg = /^a+$/;
console.log(reg.test('')); // false
console.log(reg.test('a')); // true
console.log(reg.test('aaaa')); // true
// ? 相当于 1 || 0
var reg = /^a?$/;
console.log(reg.test('')); // true
console.log(reg.test('a')); // true
console.log(reg.test('aaaa')); // false
// {3 } 就是重复3次
var reg = /^a{3}$/;
console.log(reg.test('')); // false
console.log(reg.test('a')); // false
console.log(reg.test('aaaa')); // false
console.log(reg.test('aaa')); // true
// {3, } 大于等于3
var reg = /^a{3,}$/;
console.log(reg.test('')); // false
console.log(reg.test('a')); // false
console.log(reg.test('aaaa')); // true
console.log(reg.test('aaa')); // true
// {3,16} 大于等于3 并且 小于等于16
var reg = /^a{3,6}$/;
console.log(reg.test('')); // false
console.log(reg.test('a')); // false
console.log(reg.test('aaaa')); // true
console.log(reg.test('aaa')); // true
console.log(reg.test('aaaaaaa')); // false
var reg = /^[a-zA-Z0-9_-]{6,16}$/;
// {6,16} 中间不要有空格
console.log(reg.test('a')); // =>false
console.log(reg.test('andy-red')); //=> true
console.log(reg.test('andy_red')); // => true
console.log(reg.test('andy!007')); // =>false
小括号
var reg = /^abc{3}$/; // abccc
var reg = /^(abc){3}$/ // abcabcabc
预定义符号
/**
* 正则表达式:预定义字符类
* . :匹配任何字符
* \d :表示匹配一位数字,它等价于[0-9]
* \D :表示匹配除数字以外的字符,等价于[^0-9]
* \s :表示匹配一个空白字符
* \S :表示匹配一个非空白字符,等价于[^\s]
* \w :表示匹配字母,数字和下划线,等价于[a-zA-Z_0-9]
* \W :匹配除字母、数字和下划线以外的任意字符,等价于[^\w]和[^0-9a-zA-Z_]
*/
正则替换
- replace替换字符
stringObject.replace(regexp/substr, replacement);
- 第一个参数: 被替换的字符串 或者 正则表达式
第二个参数: 替换为的字符串 - /表达式/[switch]
- switch(也称为修饰符) 按照什么样的模式来匹配. 有三种值:
g:全局匹配
i:忽略大小写
gi:全局匹配 + 忽略大小写
var text = document.querySelector('textarea');
var btn = document.querySelector('button');
btn.onclick = function(){
text.value.replace(/激情/g, '**'); // 所有激情替换为**
}