整理了一下学习js时遇到的问题,一些与其他语言相同的共性这里就省略了。
Javascrpit笔记
变量
变量提升
|
|
变量提升即变量可以引用稍后声明的变量而不会引发异常。提升即将声明提到其作用域的顶部,但是初始化却不会提升,所以赋值给a的操作无法是调用之前进行。
|
|
变量提升与变量自身的作用域有关,上述funcA因为函数内部作用域的变量i函数提升了,无法读出函数外部全局变量i,而funcB内部不存在同名变量,因此可以访问全局变量i
函数提升
|
|
对于函数,只有函数声明会被提升到顶部,而不包括函数表达式。
|
|
因为函数提升比变量提升的优先级高,所以第一个log输出函数a。
let关键字
|
|
let用来声明变量,不过与var不同,let声明的变量不能变量提升。
|
|
let声明的变量作用范围也不能超出代码块。
变量的解析顺序
|
|
局部变量优先级大于外部(全局)变量
|
|
虽然内部变量提升了,但是由于形参优先级更高,并且内部变量没有在第一个log前赋值,所以此时第一个log输出形参
|
|
由于函数提升了,函数的优先级比形参的高,所以形参x被函数x覆盖了。
|
|
参数列表中的读取的值为同个参数列表其他值
连等赋值问题
|
|
.的优先级大于=号。
- 声明a对象中的x属性,用于赋值,此时b指向a,同时拥有未赋值的x属性
- 对a对象赋值,此时变量名a改变指向到对象{n:2}
- 对步骤1中x属性,b指向的对象(a原指对象)的x属性赋值
面向对象
构造函数创建对象
js中没有类,但有构造函数可以创建新实例。
|
|
Object()构造函数创建对象
|
|
继承
Javascript的继承通过原型实现,当访问对象没定义的属性和方法时,会通过 原型链 一层一层的访问。每个对象的指针指向原型链的上一层,这个指针为proto即原型对象,一般对象的proto都指向Js的内置对象Object。
|
|
对象的proto属性的值就是它所对应的原型对象。实例才有proto,而Object.prototype指向原型对象。
prototype属性
对象定义的prototype属性是继承成员被定义的地方。不像每个对象都有proto属性来标识自己所继承的原型,只有函数才有prototype属性,当创建函数是,JS会为这个函数自动添加prototype属性,值是一个有constructor属性的对象,而不是空对象。当通过new关键进行调用此函数时,JS就会创建实例,并且通过设置此实例的proto指向构造函数的prototype来实现继承。
|
|
从打印的a实例中可知,speak方法是存在与a里的,而run方法是通过原型链(proto)访问。
构造函数的属性
|
|
定义在构造函数内的方法,可以访问到函数内部用var定义的变量
constructor属性
|
|
每个对象实例都有construction属性来指向他们的构造函数,当然也可以利用这种方式来创建新的实例。
原型式继承
|
|
Object.create()可返回一个对象所需的proto(绝对不要直接修改proto)。
因为修改了prototype,所以之后还需改回prototype中的构造器,这样就完成了Teacher类继承Person类。
new的实质
|
|
当执行上述代码时,等同于下面的:
|
|
|
|
若调用了某个方法,会先检查o是否有这个方法,没有的话会查找Object.getPrototypeOf(o).method,如果还是没有就会继续Object.getPrototypeOf(Object.getPrototypeOf(o)).method,一直递归查找。
函数
call & apply & bind
call方法和apply方法都是Function.prototype中的方法,主要作用都是将某个对象作为调用函数的上下文,来执行目标函数。
|
|
两者的第一个参数都是执行函数的 上下文对象 ,两者的区别主要是参数列表的不同,apply要求传入数组,数组中为目标函数的参数列表。而call传入的参数如果有多个的话就逗号隔开。
|
|
bind同样可以将执行函数绑定指定的this,不同的是bind返回的是一个函数而不像apply和call那样直接执行,bind是柯里化函数,可以用于延迟计算。
this
this可以理解为执行的上下文(一个对象,里面的属性局部作用域能访问到),并非函数代码中声明的位置,而执行的位置(箭头函数的this除外)。
默认绑定
|
|
一般的this绑定在全局域中,除非调用点改变全局域的值,否则主调函数内的var同名变量也不能改变this取值
浏览器中在全局域定义var变量等同于全局变量(window),但在node环境中不加var关键字才能定义全局变量。
隐含绑定
|
|
此时this绑定在obj对象中。需要注意的是即使foo函数写在obj对象内,也不是完全属于obj的,像foo()不冠以obj环境照样读取全局的a。
隐含丢失
|
|
以上情况会导致隐含丢失,看上去用的是obj的环境上下文,实际定义函数变量后在调用却是绑定全局的this。
|
|
以回调的方式传入,this同样会隐含丢失。
明确绑定
|
|
使用call,apply会让this明确绑定在指定的上下文。
硬绑定
|
|
硬绑定即有一个函数,通过给定的上下文以及调用函数,用明确绑定将其绑死,无论外部如何,也无法改变参数函数(bindFunc中的foo)里绑定的this。
javascript中Function.Prototype.bind即是如此实现硬绑定。
new绑定
|
|
new一般会返回新构建的对象,而这个对象被设置为函数调用的this,this在这个函数内部!
以上四种绑定中,new绑定 > 明确绑定 > 隐含绑定 > 默认绑定
箭头函数没有自己的this
|
|
箭头函数没有自己的this,箭头函数内的this总指向外层函数的this,所以对箭头函数进行明确绑定是无效的。
常用函数
数组
名称 | 使用例子 | 描述 |
---|---|---|
Array.from | Array.from({length:10},(v,i)=>{..}) | 用于创建数组实例 |
Array.isArray() | Array.isArray(L) | 判断是否为数组对象 |
Array.prototype.concat() | a1.concat(a2,a3,a4,…) | 返回一个组合并了多个数组的对象 |
Array.prototype.every() | a1.every(func(ele,index,arr){}) | 根据回调函数返回的布尔检查每个元素是否通过测试 |
Array.prototype.fill() | a1.fill(x) | 将数组每一项用x来填充 |
Array.prototype.filter() | a1.filter(func(ele,index,arr){}) | 根据回调函数返回的布尔筛选数组每一项 |
Array.prototype.forEach() | a1.forEach(func(ele,index,arr){}) | 对每个元素都执行一次回调函数 |
Array.prototype.find() | a.find(func(ele,index,arr){}) | 根据回调函数返回的布尔值找出第一个符合条件的元素 |
Array.prototype.findIndex() | 同上 | 跟find差不多,只是返回的是索引 |
Array.prototype.includes() | a1.includes(x) | 判断数组是否含有x元素 |
Array.prototype.indexOf() | arr.indexOf(searchElement[, fromIndex = 0]) | 找出第一个指定元素的索引 |
Array.prototype.map() | a1.map(func(ele,index,arr){return ..}) | 一个新数组,每个元素都是回调函数的结果 |
Array.prototype.push() | a.push(1,2,3,…) | 数组末尾推入元素 |
Array.prototype.pop() | a.pop() | 数组末尾删除元素,并且返回该元素 |
Array.prototype.reverse() | a1.reverse() | 返回一个原数组翻转的数组 |
Array.prototype.shift() | a1.shift() | 删除并返回第一个元素 |
Array.prototype.unshift() | a1.unshift(x,2,3,…) | 在数组开头依次添加元素 |
Array.prototype.sort() | a1.sort([func(a,b){return 0/1/-1}]) | 数组排序,会改变原数组 |
Array.prototype.splice() | a1.splice(start[, deleteCount[, item1[, item2[, …]]]]) | 删除或添加元素,若deletecount不指定,会从start删到结束,deleteCount=0表示添加元素 |
Array.prototype.slice() | arr.slice([begin,end]); | 返回元素的切片,前包后不包 |
Array.prototype.join() | a1.join(separator) | 根据连接符将元素连接成字符串 |
字符串
名称 | 使用例子 | 描述 |
---|---|---|
String.prototype.concat() | str.concat(string2, string3[, …, stringN]) | 连接字符串 |
String.prototype.trim() | str.trim() | 清除字符串左右空格 |
String.prototype.toLowerCase() | str.toLowerCase | 转小写(toUpperCase为转大写) |
String.prototype.match() | str.match(regexp) | 正则匹配字符串,返回数组,没有匹配则返回null |
String.prototype.replace() | str.replace(regexp或substr, newSubStr或function(oldStr)) | 返回替换后的新的字符串,原数组不变 |
String.prototype.search() | str.search(regexp) | 寻找目的字符串,第一个寻找成功返回其索引,否则返回-1 |
String.prototype.slice() | str.slice(beginSlice[, endSlice]) | 字符串切片,返回一个从原字符串中提取出来的新字符串 |
String.prototype.split() | str.split([separator[, limit]]) | limit限定返回数量,将字符串按分隔符分割成数组 |
String.prototype.indexOf() | str.indexOf(searchValue[, fromIndex]) | 从寻找目的值第一次出现的索引,没有则返回-1 |
String.prototype.lastIndexOf() | str.lastIndexOf(searchValue[, fromIndex]) | 寻找目的值最后出现的索引,没有则返回-1 |
String.prototype.substr() | str.substr(start[, length]) | 返回一个字符串中从指定位置开始到指定字符数的字符 |
String.prototype.substring() | str.substring(indexStart[, indexEnd]) | 返回索引范围的子串,indexEnd不存在就返回到末尾,区间为前包后不包 |