昔洛 的个人博客

Bug不空,誓不成佛

  menu
70 文章
14633 浏览
4 当前访客
ღゝ◡╹)ノ❤️

JavaScript 高级 (下)

学习内容

  • 函数进阶
    • 函数的定义和调用
    • 函数的调用方式
    • this 指向
      • 改变函数内部的 this 指向
  • 严格模式
    • 正常模式
    • 严格模式
  • 闭包(浅)
    • 高阶函数
    • 闭包
  • 深拷贝与浅拷贝
    • 浅拷贝
    • 深拷贝
  • 正则表达式
    • 正则表达式在 JS 中的使用
    • 测试正则表达式
    • 正则表达式中的特殊字符
    • 正则表达式的组成
    • 边界类
    • 字符类
      • [] 方括号
      • 量词符
    • 预定义类
    • replace 替换

一、函数进阶

① 函数的定义和调用

  1. 函数声明方式 function 关键字(命名函数)
  2. 函数表达式(匿名函数)[自调用函数/立即执行函数]
  3. // new Function()
    //var fn = new Function('参数1','参数2',...,'函数体')
    var fn = new Function('a','b','console.log(a,b)');
    fn(123,456);
    
  4. Function 里面参数都必须是字符串格式
  5. 第三种方式执行效率低,也不方便书写,因此较少使用
  6. 所有函数都是 Function 的实例(对象)
  7. 函数也是对象

② 函数的调用方式

  1. 普通函数 [fn()]
  2. 对象的方法 [obj.chang = function(){}]
  3. 构造函数 [new Fn()]
  4. 绑定事件函数 [btn.onclick = function(){}]
  5. 定时器函数 [window.setInterval(function(){})]
  6. 立即执行函数 [(function () {}()]
  7. 回调函数 [function(fn){},fn 是一个函数]
  • this 指向:当前调用者

    调用方式this指向
    普通函数调用window
    构造函数调用实例对象 原型对象里面的方法也指向实例对象
    对象方法调用该方法所属对象
    事件绑定方法绑定事件对象
    定时器函数window
    立即执行函数window
    • 改变函数内部 this 指向

      • call 方法

      call() 方法调用一个对象。简单理解为调用函数的方式,但是他可以改变函数的 this 指向。
      fun.call(thisArg, arg1, arg2, ...)
      thisArg: 在 fun 函数运行时执行的 this 值
      arg1,arg2:传递的参数值
      返回值就是函数的返回值,因为它就是调用函数
      function Father () {this}
      function Son() {Father.call(this,1,2)}

      • apply 方法

      fun.apply(thisArg, [argsArray]):调用函数
      thisArg:在 fun 函数运行时指定的 this 值
      argsArray:传递的值,必须包含在数组里面
      返回值就是函数的返回值,因为他就是调用函数
      因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值

      • bind 方法

      bind() 方法不会调用函数,但是能改变函数内部 this 指向
      fun.bind(thisArg, arg1, arg2, ...)
      thisArg:在 fun 函数运行时指定的 this 值
      arg1,arg2:传递的其他参数
      返回由指定的 this 值和初始化参数改造的原型数拷贝
      因此只是想改变 this 指向,并不想调用这个函数的时候,可以使用 bind

      • call apply bind 总结

      相同点:都可以改变函数内部的 this 指向
      区别点:

      1. call 和 apply 会调用函数,并且改变函数内部的 this 指向
      2. call 和 apply 传递的参数不一样,call 传递参数 arg1, arg2..形式,apply 必须数组形式传参 [arg]
      3. bind 不会调用函数,可以改变函数内部 this 指向
        主要应用场景:
      4. call 经常做继承
      5. apply 经常跟数组有关系,比如借助于数学对象实现数组的最大值最小值
      6. bind 不调用函数,但是还想改变 this 指向,比如改变定时器内部的 this 指向

二、严格模式

JavaScript 除了提供正常模式外,还提供了严格模式(strictmode)。ES5 的严格模式是采用具有限制性 JavaScript 变体的一种方式,即在严格的条件下运行 JS 代码。
严格模式在 IE10 以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略。
严格模式对正常的 JavaScript 语义做了一些更改:

  1. 消除了 JavaScript 语法的一些不合理、不严谨之处,减少了一些怪异行为。[例如变量,不生命就报错]
  2. 消除代码运行的一些不安全之处,保证代码运行的安全
  3. 提高编译器效率,增加运行速度
  4. 禁用了在 ECMAScript 的未来版本中可能会定义的一些语法,为未来新版本的 JavaScript 做好铺垫。比如一些保留字如:class,enum,export,extends,import,super 不能做变量名

① 开启严格模式

开启严格模式:"use strict"

<script>"use strict"</script>:脚本开启严格模式
<script>function fn() {"use strict"}</script> 为函数开启严格模式

/*
严格模式可以应用到整个脚本或个别函数中,因此在使用时,我们可以将严格模式分为为脚本开启严格模式和为函数开启严格模式的两种情况
*/
  • 为脚本开启严格模式

    为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 "use strict" 或 'use strict';
    <script>
    "use strict";
    console.log('这是严格模式');
    </script>
    因为 "use strict" 加了引号,所以老版本的浏览器会把它当作一行普通字符串而忽略。

  • 为函数开启严格模式

    要给某个函数开启严格模式,需要把 "use strict" 或 'use strict' 声明放在函数体所有语句之前。
    function fn() {"use strict"; return "这是严格模式";}
    将 "use strict" 放在函数体的第一行,则整个函数以 "严格模式"运行。

② 严格模式中的变化

  • 变量规定:变量声明必须加 var,而且不准删除变量

    在正常模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止使用这种用法,变量都是必须先用 var 命令声明,然后再使用。
    严禁删除已经声明的变量。例如 delete x; 语法是错误的。

  • 严格模式下的 this 指向问题

    以前在全局作用域函数中的 this 指向 window 对象。
    严格模式下全局作用域中函数中的 this 是 undefined。
    其他的没有变化:

    1. 以前构造函数时不加 new 也可以调用,当普通函数,this 指向全局对象
    2. 严格模式下,如果构造函数不加 new 调用,this 指向的是 undefined 如果给他赋值则会报错 new 实例化的构造函数指向创建的对象实例
    3. 定时 this 还是指向 window
    4. 事件、对象还是指向调用者
  • 函数变化

    函数不能有重名的参数
    函数必须声明在顶层,新版本的 JavaScript 会引入 "块级作用域" (ES6 中已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数。[if,for 等里面定义函数也不可以,但是现在不可以]
    更多严格模式要求可参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode
    错误写法:
    function fn (a,a) {console.log(a+a);}
    fn(1,2);

三、闭包(浅)

① 高阶函数

高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出
高阶函数:函数作为参数传递或者函数作为返回值返回,就是高阶函数,典型的例子就是回调函数。

② 闭包

① 变量作用域

通常情况下有如下说明:
变量根据作用域的不同分为两种:全局变量和局部变量

  1. 函数内部可以使用全局变量。
  2. 函数外部不可以使用局部变量。
  3. 当函数执行完毕,本作用域内的局部变量会销毁。

② 什么是闭包

  • 闭包作用:延伸变量的作用范围。

闭包(closure)指有权访问另一个函数作用域中变量的函数。【很多种解释,但都没有真正的一个定义标准】
简单理解就是:一个作用域可以访问另外一个函数内部的局部变量。
<script>
function fn1() {
// fn1 就是闭包函数
var num = 10;
function fn2() {
console.log(num); // 10
}
fn2()
}
fn1();
</script>

  • 在外部使用访问函数内部的变量
function fn() {
	var i = 7;
	return function() {
		console.log(i);
	}
}
var n = fn();
n();

四、深拷贝与浅拷贝

// 拷贝不能直接赋值,对象赋值的是地址
var obj = {
	name : '张三丰',
	age : 22
	};
var newObj = obj;
console.log(newObj);
  • 浅拷贝:只拷贝最外面一层
var obj = {
	name : '张三丰',
	age : 22
};
var newObj = {};
for( var key in obj ) {
	newObj[key] = obj[key];
}
console.log(newObj);
// es6:新方法
Object.assign(target,sources);
  • 深拷贝
var obj = {
	name : '1张三丰',
	age : 22,
	messige : {
		sex : '男',
		score : 16
	},
	color : ['red','purple','qing']

}

var newObj = {};

function kaobei (newObj,obj) {
	for (key in obj) {
		if (obj[key] instanceof Array) {
			newObj[key] = [];
			kaobei(newObj[key],obj[key]);
		} else if (obj[key] instanceof Object) {
			newObj[key] = {};
			kaobei(newObj[key],obj[key])
		} else {
			newObj[key] = obj[key];
		}
	}
}
obj.messige.sex = 99;
kaobei(newObj,obj);
console.log(newObj);

此外,还可以利用 JSON 对复杂类型对象进行复制,使用 JSON.parse(JSON.stringify(data)) 就可以复制出一份新的复杂类型对象,可以避免手动写方法进行拷贝。

五、正则表达式

  • 创建正则表达式
    在 JavaScript 中,可以通过两种方式创建一个正则表达式。

    • 方式一:通过调用 RegExp 对象的构造函数创建
      var regexp = new RegExp(/123/);
    • 方式二:利用字面量创建 正则表达式
      var rg = /abc/;含义:只要包含 abc 就可以
  • 测试正则表达式

    • test() 正则对象方法,用于检测字符串是否符合该规则,该对象会返回 true 或 false,其参数是测试字符串
    • 正则里面没有引号
      regexObj.test(str);
      regexObj:正则表达式
      str:用户输入字符串
  • 正则表达式中的特殊字符

    正则表达式可以由简单的字符构成,比如 /abc/,也可以是简单和特殊字符的组合,比如 /ab*c/。其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如 ^、$、+
    正则表达式:简单字符 和 特殊字符[元字符]
    特殊字符很多,可参考:
    MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
    jQuery 手册:正则表达式部分
    正则测试工具:http://tool.oschina.net/regex

    正则:匹配字符串
    1、创建珍珠铬[new RegExp(/abc/),var str = /abc/;]
    2、测试 [reg.test(str)]
    3、表达式:简单字符和特殊字符

  • 边界符

    • 正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符
      ^:表示匹配行首的文本(以谁开始)[/^abc/:以 abc 为开头]
      $:表示匹配行尾的文本(以谁结束)[/^abc$/:只能是 abc]
    • 如果 ^ 和 $ 在一起,表示必须是精确匹配
    	var rg = /abc/; // 正则表达式里面不需要加引号 不管是数字型还是字符串型
    	// /abc/ 只要包含有abc这个字符串返回的都是true
    	console.log(rg.test('abc'));
    	console.log(rg.test('abcd'));
    	console.log(rg.test('aabcd'));
    	console.log('---------------------------');
    	var reg = /^abc/;
    	console.log(reg.test('abc')); // true
    	console.log(reg.test('abcd')); // true
    	console.log(reg.test('aabcd')); // false
    	console.log('---------------------------');
    	var reg1 = /^abc$/; // 精确匹配 要求必须是 abc字符串才符合规范
    	console.log(reg1.test('abc')); // true
    	console.log(reg1.test('abcd')); // false
    	console.log(reg1.test('aabcd')); // false
    	console.log(reg1.test('abcabc')); // false
    
  • 字符类

    字符类表示有一系列字符可供选择,只要匹配其中一个就可以了,所有可供选择的字符都放在方括号内。

  • [] 方括号

    	表示有一系列字符可供选择,只要匹配其中一个就可以了【多选1】
    	var rg = /[abc]/; // 只要包含有a 或者 包含有b 或者包含有c 都返回为true
    	console.log(rg.test('andy'));//true
    	console.log(rg.test('baby'));//true
    	console.log(rg.test('color'));//true
    	console.log(rg.test('red'));//false
    	var rg1 = /^[abc]$/; // 三选一 只有是a 或者是 b  或者是c 这三个字母才返回 true
    	console.log(rg1.test('aa'));//false
    	console.log(rg1.test('a'));//true
    	console.log(rg1.test('b'));//true
    	console.log(rg1.test('c'));//true
    	console.log(rg1.test('abc'));//true
    	----------------------------------------------------------------------------------
    	var reg = /^[a-z]$/ //26个英文字母任何一个字母返回 true  - 表示的是a 到z 的范围  
    	console.log(reg.test('a'));//true
    	console.log(reg.test('z'));//true
    	console.log(reg.test('A'));//false
    	-----------------------------------------------------------------------------------
    	//字符组合
    	var reg1 = /^[a-zA-Z0-9]$/; // 26个英文字母(大写和小写都可以)任何一个字母返回 true  
    	------------------------------------------------------------------------------------
    	//取反 方括号内部加上 ^ 表示取反,只要包含方括号内的字符,都返回 false 。
    	var reg2 = /^[^a-zA-Z0-9]$/;
    	console.log(reg2.test('a'));//false
    	console.log(reg2.test('B'));//false
    	console.log(reg2.test(8));//false
    	console.log(reg2.test('!'));//true
    
    	/^[^a-z]$/:两个^,括号外面的是便边界,括号里面的是取反的含义
    
  • 量词符

    词符用来设定某个模式出现的次数。[a-z]量词

    量词说明
    *重复0次或更多次[>=0次] /^[a-z]*$
    +重复1次或更多次[>=1词] /^[a-z]+$/]
    ?重复0词或1次
    {n}重复 n 次
    {n,}重复 n 次或更多次
    {n,m}重复 n 到 m 次

    注意:{n,m} n和m之间不能有空格

  • 括号总结:

    • 大括号:量词符,里面表示重复次数
    • 中括号:字符集合,匹配方括号中的任意字符。
    • 小括号表示优先级
    • 正则表达式在线测试 : https://c.runoob.com
  • 预定义类

    • 预定义指的是某些常见模式的简写方式。
      img3.png
  • replace 替换:

    • 语法:/表达式/[修饰符]
    • g:全局匹配
    • i:忽略大小写
    • gi:全局 + 忽略
希望所有的 Bug 都会报错~