JS高级【二】---闭包,深浅拷贝,正则

1. 函数的定义和使用

  • 所有的函数都是 Function的实例对象
  • 函数也属于对象

image-20210127120808459

函数内this指向,更全面版

image-20210127121447800
		// 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, '**');  // 所有激情替换为**
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值