一、insertAdjacentHTML()
说明:该方法可以直接将以字符串形式创建的元素添加到 dom 中,比 innerHtml 操作更快
语法:
element.insertAdjacentHTML(position, text)
position:将元素插入的位置
text:插入的元素,可以直接写成字符串,可以写变量
position 的值有:
beforebegin:元素自身的前面
afterend:元素自身的后面
afterbegin:元素内部的第一个子节点之前
beforeend:元素内部的最后一个子节点之后
其它的注意事项搜索网址:https://developer.mozilla.org/zh-CN/docs/Web/API/Element/insertAdjacentHTML
二、双击禁止选中文字
在双击事件里写入这段代码即可:
window.getSelection?window.getSelection().removeAllRanges():document.selection.empty()
三、构造函数和原型
1 概述:
① 在典型的OOP的语言中 (如Java),都存在类的概念,类就是对象的模板,对象就是类的实例,但在ES6之前,
JS 中并没用引入类的概念。
② ES6,全称 ECMAScript 6.0,2015.06发布。但是目前浏览器的JavaScript是ES5版本,大多数高版本的浏览
器也支持ES6,不过只实现了ES6的部分特性和功能。
③ 在ES6之前,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和它们的特征。
注意:构造函数的语法在之前的 Web笔记之JavaScript 中提到
2 构造函数
说明:JavaScript的构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数
内部的this上添加。通过这两种方式添加的成员,就分别称为静态成员和实例成员。
① 静态成员:在构造函数本身上添加的成员称为静态成员,只能由构造函数本身来访问
例如:
function Star(age) {
this.age = age;
this.sing = function() {
console.log('唱歌')
}
}
var zzh = new Star(18)
Star.sex = '男'; //在构造函数本身上添加
console.log(Star.sex) //可以成功打印 男
console.log(zzh.sex) //打印结果为 undefined,不可以通过对象去访问静态成员
② 实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问
例如:
function Star(age) {
this.age = age;
this.sing = function() {
console.log('唱歌')
}
}
var zzh = new Star(18)
console.log(zzh.age) //可以成功打印 18
zzh.sing() //可以成功调用函数,打印结果为 唱歌
console.log(Star.age) //打印结果为 undefined,不可以通过构造函数本身去访问实例成员
3 构造函数的问题以及解决方法
构造函数方法很好用,但是存在浪费内存的问题:
① 每次实例化一个对象,如果对象里有方法,内存就会开辟一个空间存储这个方法,那么,如果需要实例化100个
对象,内存就会开辟100个空间存储这个方法,关键是这个方法的代码是一样的,那这样就会造成内存的浪费
② 因为内存是通过地址进行存储的,虽然方法名相同,但存放的地址不同,所以每个实例化对象里的方法都是不同的
解决方法:
开辟一个空间,里面存放的是对象的公共方法,然后让每一个对象都指向这个空间,这样就解决了问题,那么该如何
去开辟这个空间呢?js 提供了 prototype 这个对象来开辟空间
4 构造函数原型 prototype
说明:
① JavaScript规定,每一个构造函数都有一个 prototype 属性,注意这个 prototype 是一个对象,
这个对象里的所有属性和方法,都归于构造函数所有。
② 可以把相同的方法直接写在 prototype 对象里,这样所有的实例化对象都可以共享这些方法。
例子:
function Star(age) {
this.age = age;
}
Star.prototype.sing = function() {
console.log('唱歌')
}
var zzh = new Star(18)
var hongm = new Star(20)
console.log(zzh.sing === hongm.sing) //打印结果为true
zzh.sing() //调用成功,打印结果为唱歌
总结:一般情况下,公共属性写到构造函数里面,公共方法写到 prototype 里面
5 对象原型 __proto__
① 对象之所以可以使用构造函数原型 prototype 的属性和方法,是因为对象有 __proto__ 原型的存在,
__proto__ 会指向构造函数原型 prototype
② 对象原型 __proto__ 和 构造函数原型 prototype 是等价的
③ __proto__ 对象原型的意义在于为对象的查找机制提供一个方向,或者说一条路线,但它是一个
非标准属性,因此在实际开发中,不可以使用这个属性,它只是内部指向构造函数原型 prototype,没有其它用途
对象调用方法的查找规则:
先查找对象本身有没有该方法,有就调用,没有再去查找构造函数原型 prototype 是否有该方法,有就调用
6 constructor 构造函数
① 对象原型 __proto__ 和 构造函数原型 prototype 里面都有一个 constructor 属性,constructor 也是一个构造函数,
因为它指向构造函数本身。
② constructor 主要用于记录该对象是引用了哪个构造函数,它可以让原型对象重新指向原来的构造函数。
③ 如果是通过对象赋值的形式给 prototype 添加方法,那么要让 constructor 指向原来的构造函数,例如:
Star.prototype = {
constructor : Star,
sing : function() {
console.log(66)
}
}
7 原型链
箭头的含义是,某种东西可以通过某种介质去访问某种东西,比如:
ldh 对象通过 __proto__ 去访问 Star 原型对象 prototype,其它箭头同理
8 JavaScript 的成员查找机制 (规则)
① 当访问一个对象的属性或方法时,首先查找这个对象自身有没有该属性或方法。
② 如果没有就查找它的构造函数原型(也就是 __proto__ 指向的 prototype )。
③ 如果还没有就查找 Object 的原型对象。
④ 如果Object 的原型对象还是没有,就会返回 undefined,结束查找
9 构造函数中的 this 指向问题
无论是构造函数中的 this,还是构造函数原型 prototype 中的 this,都是指向实例对象
10 扩展内置对象
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求和的功能。例如:
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum = sum + this[i]
}
return sum
}
// var arr = [1,2,3] 这种方式创建数组也可以
var arr = new Array(1,2,3)
console.log(arr.sum()); //成功打印 6
注意:给内置对象添加方法只能使用追加的形式,比如:Array.prototype.xxx = function() { },不能使用
对象赋值的形式给 prototype 添加方法
四、继承
说明:ES6之前并没有给 js 提供 extends 继承。但可以通过构造函数+原型对象模拟实现继承,被称为组合继承
1 call( )
说明:该方法可以调用函数,也可以修改 this 指向
语法:
函数名.call(thisArg, arg1, arg2, .....)
thisArg:修改当前函数的 this 指向,即 this 指向谁
arg1,arg2:向当前函数传递参数
注意:必须要有 thisArg,否则 arg1,arg2 无效,即无法传递参数
2 借用构造函数继承父类型属性
思路:通过 call() 把父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性。
例子:
function Father(uname, age) {
this.uname = uname;
this.age = age;
}
function Son(uname, age) {
//通过 call() 把父类型的this指向子类型的this
Father.call(this,uname, age)
}
var son = new Son('zzh', 18)
console.log(son.age); //成功打印 18
3 借用原型对象继承父类型方法
function Father(uname, age) {
this.uname = uname;
this.age = age;
}
function Son(uname, age) {
Father.call(this, uname, age)
}
Father.prototype.money = function() {
return '赚钱'
}
// 不能 Son.prototype = Father.prototype
Son.prototype = new Father()
Son.prototype.constructor = Son;
Son.prototype.exam = function() {
return 100
}
var son = new Son('zzh', 18)
console.log(son);
console.log(Son.prototype);
console.log(son.money());
console.log(Father.prototype);
五、ES5 中新增的方法
1 数组方法
遍历(迭代)方法:
forEach(),map(),filter(),some(),every()
forEach() 语法:
数组名.forEach(function(value, index, array) {
})
● value:每个数组元素
● index:每个数组元素的索引
● array:数组本身
● 这三个参数用到谁写谁,不一定全都要写
● return 无法终止遍历
filter() 语法:
说明:该方法可以对数组的元素进行筛选并且会创建一个新数组,符合条件的元素会返回到新数组里,不会影响原数组
数组名.filter(function(value, index, array) {
})
● value:每个数组元素
● index:每个数组元素的索引
● array:数组本身
● 这三个参数用到谁写谁,不一定全都要写
● return 无法终止遍历
注意:
它直接返回一个新数组
例子:
var arr = [11,22,33,6]
var newArr = arr.filter(function(value,index) {
return value >= 10
})
console.log(newArr); //打印的结果为 [11, 22, 33]
some() 语法:
说明:该方法可以对数组的元素进行检测,符合条件的元素会返回 true,不符合条件的返回 false
数组名.some(function(value, index, array) {
})
● value:每个数组元素
● index:每个数组元素的索引
● array:数组本身
● 这三个参数用到谁写谁,不一定全都要写
注意:
① 它返回的值是布尔类型
② 如果找到第一个满足条件的元素,则终止循环不再继续往下查找
③ 如果是查询数组中的唯一元素,建议使用 some()
④ return true 就会终止循环,可以提高遍历效率
例子:
var arr = [11,22,33,6]
var newArr = arr.some(function(value) {
return value >= 11
})
console.log(newArr); //打印的结果为 true
以上是常用的方法,其它方法去百度
2 字符串方法
trim() 语法:
说明:该方法会删除一个字符串两端的空白字符,并返回一个新的字符串,不影响原字符串
例子:
str.trim()
3 对象方法
Object.keys()
说明:用于获取对象自身所有的属性
语法:
object.keys(obj)
参数说明:
obj:目标对象,即给哪个对象进行操作
注意:
① 该方法效果类似 for...in
② 返回一个由属性名组成的数组
Object.defineProperty()
说明:定义新属性到对象中 或 修改原有的对象属性。
语法:
object.defineProperty(obj, 'prop', descriptor)
参数说明:
obj:目标对象,即给哪个对象进行操作,必填
prop:定义新属性到对象中 或 修改原有的对象属性,必填
descriptor:目标对象的属性所拥有的特性,是以对象的形式书写,必填
descriptor 的参数选项:
● value:设置属性的值,默认为 undefined
● writable:属性值是否可以在外部进行重写(修改),默认为 false
● enumerable:属性是否可以在外部进行重写被枚举(遍历),默认为 false
● configurable:属性是否可以被删除 或 是否可以再次修改特性,默认为 false
注意:以上这四个参数只要有 object.defineProperty() 就会产生
例子:
Object.defineProperty(data,'price',{
value: 9,
writable: true
})
六、函数
1 call() 方法及其应用
在第四小节的继承提到,该方法主要用来实现继承操作
2 apply() 方法及其应用
说明:
apply() 方法可以调用一个函数并且可以改变函数的this指向。
语法:
函数名.apply(thisArg, [argsArray])
① thisArg:在函数运行时指定的this值
② [argsArray]:传递的值,必须是一个数组
③ 返回值就是函数的返回值,因为它就是调用函数
④ 数组传递什么类型,函数就拿到什么类型
主要用途:
比如说可以利用apply()借助于数学内置对象求数组最大值,代码如下:
var arr = [1,2,3];
var max = Math.max.apply(Math,arr)
console.log(max); //打印结果为 3
3 bind() 方法及其应用
说明:
bind() 能改变函数内部的this指向,但是不会调用函数
语法:
函数名.bind(thisArg, arg1, arg2, .....)
① thisArg:在函数运行时指定的this值
② arg1,arg2:传递的参数
③ 会返回指定的 this 值和初始化参数改造的原函数拷贝,例子:
var o = {
name: 'pink'
}
function fn() {
console.log(this);
}
var f = fn.bind(o);
f();
主要应用:
比如,有一个按钮,当点击了之后,就禁用这个按钮,3杪钟之后再开启这个按钮,代码如下:
var btn = document.querySelector('button');
btn.onclick = function() {
this.disabled = true;
setTimeout(function() {
this.disabled = false;
}.bind(this),3000)
}
七、严格模式
1 简介:
① JavaScript除了提供正常模式外,还提供了严格模式( strict mode )。ES5的严格模式是采用
具有限制性JavaScript变体的一种方式,即在严格的条件下运行JS代码。
② 严格模式在IE10以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略。
③ 严格模式对正常的JavaScript语义做了一些更改:
(1) 消除了Javascript语法的一些不合理、不严谨之处,减少了一些怪异行为。
(2) 消除代码运行的一些不安全之处,保证代码运行的安全。
(3) 提高编译器效率,增加运行速度。
(4) 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的Javascript做
好铺垫。比如 class,enum,export,extends,import,super 等关键字不能作为变量名
2 开启严格模式
① 说明:
严格模式可以应用到 整个JS 或 单独的函数中。因此在使用时,可以将严格模式分为 脚本
开启严格模式 和 函数开启严格模式两种情况。
② 脚本开启严格模式
为整个JS开启严格模式,只需在 JS 代码的第一行写一行语句即可。比如:
<script>
'use strict';
.........以下写JS代码
</script>
③ 函数开启严格模式
给某个函数开启严格模式,只需在函数内部的第一行加入 'use strict' 语句即可。比如:
function fn() {
'use strict'
........以下写JS代码
}
注意:
因为 "use strict" 加了引号,所以老版本的浏览器会把它当作一行普通字符串而忽略。
3 严格模式下对正常模式的限制
查看地址:https://www.runoob.com/js/js-strict.html
八、高阶函数
1 简介
高阶函数是对其他函数进行操作的函数,它接收函数作为参数 或 将函数作为返回值输出。
2 接收函数作为参数
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用。最典型的就是作为回调函数。
例子:
function fn(callback) {
callback && callback();
}
fn(function callback() {
console.log(666); // 结果打印 666
})
九、闭包
1 简介
闭包 (closure)指有权访问另一个函数作用域中变量的函数。
简单理解就是,一个作用域可以访问另外一个函数内部的局部变量。
2 闭包的作用
延伸了变量的作用范围
例子:
function fn() {
var num = 666
return function() {
console.log(num); /成功打印 666
}
}
var f = fn()
f()
十、递归函数
1 简介
① 如果一个函数在内部调用其本身,那么这个函数就是递归函数。
② 简单理解,就是函数内部自己调用自己,这个函数就是递归函数
③ 递归函数的作用与循环相同
④ 由于递归很容易发生 “栈溢出” 错误 (stack overflow),所以必须要加退出条件 return。
十一、对象拷贝(复制)
1 浅拷贝
说明:
浅拷贝是把被拷贝的对象复杂数据类型中的地址拷贝给目标对象,修改目标对象会影响被拷贝对象
语法:
ES6 新增方法可以实现浅拷贝
Object.assign(target, object, .........)
参数说明:
① target:目标对象,指拷贝给谁
② object:源对象,指被拷贝的对象
③ 如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的属性会覆盖前面的属性。
④ 如果该函数只有一个参数,当参数为对象时,直接返回该对象;当参数不是对象时,会先将参数转
为对象然后返回。
2 深拷贝
说明:
深拷贝是完全克隆(拷贝的是对象,而不是地址),修改目标对象不会影响被拷贝对象,但会在内存中开辟一个
空间存储新的对象。
语法:
JSON.parse(JSON.stringify(object))
参数说明:
① object:源对象,指被拷贝的对象
② 该方法必须定义一个变量来接收它返回的结果
十二、正则表达式
1 简介
① 正则表达式 (Regular Expression) 是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象。
2 作用
正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本,例如验证表单:用户名表单只能输入
英文字母、数字或者下划线,昵称输入框中可以输入中文(匹配)。此外,正则表达式还常用于过滤
掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等。
3 特点
① 灵活性、逻辑性和功能性非常的强。
② 可以迅速地用极简单的方式达到字符串的复杂控制。
③ 对于刚接触的人来说,比较晦涩难懂。
④ 实际开发中,一般都是直接复制写好的正则表达式,然后按照需求修改正则表达式。
4 创建正则表达式
① 通过调用 RegExp 对象的构造函数创建
var 变量名 = new RegExp(/表达式/);
② 通过字面量创建
var 变量名 = /表达式/;
5 正则表达式 test() 函数
test() 正则对象方法,用于检测字符串是否符合该规则,该方法会返回 true 或 false,其参数是测试的字符串。
语法:
regexObj.test(str)
参数说明:
① regexObj:正则表达式
② str:要测试的文本
6 正则表达式的组成
一个正则表达式可以由简单的字符构成,比如/abc/,也可以由简单字符和特殊字符组合构成,比如/ab*c/。
其中特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如^、$、+等。
特殊字符非常多,可以参考∶
① https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
② 正则表达式工具:https://tool.oschina.net/regex#
7 正则表达式特殊字符的分类
① 边界符
正则表达式中的边界符(位置符) 用来提示字符所处的位置,主要有两个字符:^ 与 $,如果
这两个字符在一起则表示为精确匹配
② 字符类
字符类表示有一系列字符可供选择,只要匹配其中一个就可以了。所有可供选择的字符都放在中括号内。
(1) 字符组合
/^[a-z0-9]$/.test('a') // true
中括号内部可以使用字符组合,这里表示包含a到z的26个英文字母和0到9的数字都符合,但只能
判断一个。
(2) [^]中括号内部取反符^
/^[^abc]$/.test('a') //false
这里表示abc都不符合
③ 量词符
量词符用来设定某个模式出现的次数。
量词符有 *,+,?,{n},{n,},{n,m}
④ 预定义类
预定义类指的是某些常见模式的简写方式。
符号有:\d,\D,\w,\W,\s,\S
8 正则表达式中的替换
1 replace()
replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。
stringObject.replace(regExp/substr,replacement)
参数说明:
① regExp/substr:被替换的字符串 或 正则表达式
② replacement:替换的字符串
③ 返回值是一个替换完毕的新字符串,所以要拿一个变量接收它
9 正则表达式的参数
语法:
/正则表达式/[switch]
参数说明:
switch(也称为修饰符)指按照什么样的模式来匹配,有三种值:
① g:全局匹配
② i:忽略大小写
③ gi:全局匹配+忽略大小写
使用:
一般搭配 replace() 方法使用,例子:
<body>
<textarea></textarea>
<button type="button">提交</button>
<div></div>
</body>
<script>
var textarea = document.querySelector('textarea')
var button = document.querySelector('button')
var div = document.querySelector('div')
button.onclick = function() {
div.innerHTML = textarea.value.replace(/fuck|Shit/gi,'***')
}
</script>
当你在多行文本域输入的内容含有fuck,shit,就会被替换成***,展现在div里,比如输入
的是what the Fuck Shit,点击提交按钮之后,在div里展示的是what the *** ***,就起到了
过滤(屏蔽)消息的作用。
10 正则表达式 exec() 函数
exec() 函数用于检索字符串中的正则表达式的匹配。如果字符串中有匹配的值,则返回该匹配值,否则返回null。
① 语法:
regexObj.exec(str)
参数说明:
① regexObj:正则表达式
② str:要检索的文本
② 实例:
let str = 'love'
let reg = /e/
let regResult = reg.exec(str)
console.log(regResult);
代码解释:
打印的结果为 ["e", index: 3, input: "love", groups: undefined],是一个数组,第一个元素 "e" 是
匹配到的内容。
11 分组
正则表达式中 ( ) 包起来的内容表示一个分组,可以通过分组来提取自己想要的内容,示例代码如下:
let str = '<div>我是{{name}}</div>'
let par = /{{([a-z]+)}}/
let parResult = par.exec(str)
console.log(parResult);
代码解释:
打印的结果为 ["{{name}}", "name", index: 7, input: "<div>我是{{name}}</div>", groups: undefined],
想用分组必须要用 exec() 函数,第一个元素 "{{name}}" 表示匹配到的内容,第二个元素 "name" 表示
提取出来的内容