JavaScript基础
1 变量类型和计算
1.1 值类型和引用类型的区别?
值类型:每个变量都会存储各自的值。不会相互影响
引用类型:不同变量的指针执行了同一个对象(数组,对象,函数)
1.2 typeof可以及检测的数据类型有哪些?
Note
基本数据类型:Undefined null bool string number
关键点:typeof只能区分值类型,不能区分引用类型
JS中的基本数据类型:null, undefined, bool, string, number(typeof可以区分除了null以外的四种值类型)
typeof 6种类型:Object({},[],null), Undefined, Boolean, Number, Function, String
typeof可以区分值类型,typeof null = Object
1.3 JS中===和==的区别?
1.3.1 区别?
== 会进行强制类型转换之后再比较,=== 不会进行强制类型转换的
1.3.2 应用场景?
(用于判断对象属性是否存在):if (obj == null) ===>>> 等价于if (obj == null || obj == undefined),可以简化代码,其他情形都使用===进行比较
用于判断函数的参数是否存在: function(a, b){ if(a == null) { // ... }}
对于函数内部或者是一个对象的参数进行判断只会出现undefined, 而不会报错(慎用)
1.3.3 其他?
js中类型转换为false的有哪些(6种):null, undefined, NaN, '', false, 0
1.4 JS中的内置函数有哪些?
Note
内置函数: Object Array Boolean Number String Function Date RegExp Error
内置对象:Math, JSON
2 原型和原型链
2.1 原型链的5条规则
所有的引用类型(数组,对象,函数),都是具有对象特性的,即可以自由扩展属性(除了null以外)
所有的引用类型(数组、对象、函数),都有一个proto 属性(隐式原型),这个属性的值是一个普通对象
所有的函数,都有一个prototype属性(显式原型),这个属性值是一个普通的对象
所有的引用类型(数组、对象、函数),proto的属性值指向(完全相等)它的构造函数的“prototype”的属性值
当试图得到一个对象的某一个属性的时候,如果一个对象本身没有这个属性的话,就会去它的proto( 也就是它的构造函数中去寻找这个属性)
2.2 JS中寻找对象属性的过程
当一个对象没有这个toString()这个属性的时候,就回去自己的隐式原型proto中去寻找这个属性,也就是去自己额构造函数的显示原型prototype中寻找这个属性(对象自身的隐式原型就是他的构造函数的显式原型)
发现FOO.prototype中也没有这个toString属性,这也是一个对象,name就去这个对象{}的proto中寻找toString()这个属性
2.3 instanceof的作用?
是用于判断【引用类型】属于哪个【构造函数】的方法
Note
总结:f.proto 一层一层向上寻找,能否找到FOO.prototype,找到为true,否则为false
2.4 写一个原型继承的例子
2.5 描述一下new一个对象的过程
Note
创建一个新对象
this指向这个新对象
执行代码(对this赋值)
返回this
2.6 zepto或其他框架中是如何实现原型链的?
3 作用域和闭包
3.1 函数表达式和函数声明的区别?
函数声明中函数名是必须的,函数表达式中则是可选的。
用函数声明定义的函数,函数可以在函数声明之前调用,而用函数表达式定义的函数则只能在声明之后调用。
Note
总结:( 根本原因在于解析器对于这两种定义方式读取的顺序不同:解析器会实现读取函数声明,即函数声明放在任意位置都可以被调用;而对于函数表达式,解析器只有在读到函数表达式所在那一行时才会开始执行)
3.2 对执行上下文的理解?
Note
执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。
a. 全局环境:JavaScript代码运行起来会首先进入的环境
b. 函数环境:当函数被调用执行时,会进入被调用的函数中执行代码
c. eval(不推荐使用会对JS的执行效率产生影响)
因此在一个JavaScript程序中,必定会产生多个执行上下文,JavaScript引擎会以栈的方式来处理它们,这个栈,我们称其为函数调用栈(call stack)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。当代码在执行过程中,遇到以上三种情况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕之后,就会自动出栈。
上面代码函数调用栈的过程:
参考:https://www.cnblogs.com/ashen137/p/11422136.html
3.3 对this的理解?
作为构造函数执行
作为对象属性执行
作为普通函数执行
call apply bind
3.3.1 setTimeout、setInterval中的this
从上述例子中可以看到setTimeout,setInterval中函数内的this是指向了window对象,这是由于setTimeout(),setInterval()调用的代码运行在与所在函数完全分离的执行环境上。这会导致这些代码中包含的 this 关键字会指向 window (或全局)对象。
3.3.2 严格模式下的this
(1)全局作用域中的this
在严格模式下的全局作用域中 this 指向window对象
(2)全局作用域中函数中的this
严格模式下: 在全局作用域中函数的 this 指向 undefined
(3)对象的方法中的this
严格模式下,对象的函数中的this指向该对象
(4)构造函数中的this
严格模式下,构造函数中的this指向new出来的对象
(5)事件处理函数中的this
3.3.3 箭头函数中的this
首先,箭头函数没有自己的this,箭头函数中的this是在定义函数的时候绑定,它会捕获其所在的上下文的this作为自己的this,而不像普通函数那样是在执行函数的时候绑定。
箭头函数this指向它定义时的上下文(在这里是window),而普通函数的this则指向调用它的对象 参考博文:https://blog.csdn.net/lizhengxv/article/details/84639342
3.4 call,apply,bind的区别
3.4.1 相同点
三个函数都会改变this的指向(调用这三个函数的函数内部的this)
3.4.2 不同点
1)、bind会产生新的函数,(把对象和函数绑定死后,产生新的函数)
2)、call和apply不会产生新的函数,只是在调用时,绑定一下而已。
3)、call和apply的区别,第一个参数都是要绑定的this,apply第二个参数是数组(是函数的所有参数),call把apply的第二个参数单列出来。
3.5 对JS中作用域的理解?
Note
注意点:JS是没有块级作用域的,只有函数和全局作用域
3.6 什么是自由变量和作用域链?
Note
自由变量:当前作用域没有定义的变量,就是‘自由变量’, 这里的变量是一个aaaaa,发现这个函数作用域里面没有定义这个变量,就开始去父级作用域中寻找aaaaa这个变量(全局作用域中),发现还是没有找到这个变量的定义, 最终就会报错。
作用域链:实际上就是函数作用域中没有定义的变量,会去它的父级作用域中寻找的过程。
3.7 闭包的使用场景有哪些?
3.7.1 函数作为返回值
一个函数的返回值是一个函数,父级作用域是指,定义时候的作用域,而不是执行的作用域
3.7.2 函数作为参数传递
【重点】:函数作用域中的自由变量会在声明的父级作用域中去寻找,而不是去执行的时候的作用域中去寻找变量
3.8 创建10个a标签,点击的时候,弹出对应的序号
3.9 对函数curry化的理解?
需求:要实现一个这样的加法函数,使得:add(1,2,3)(1)(2)(3)(4,5,6)(7,8)() === 42
分析这个函数的特点: 当这个函数有参数的时候,返回的是一个函数
如果没有参数的时候,就会去执行这个函数,得到计算的结果
3.10 如何实现一个bind函数?
4 异步和单线程
4.1 什么是异步?前端使用异步的场景有哪些?
4.2 如何实现一个自己的ajax?
5 其他知识点
5.1 如何获取2017-06-10 格式的日期?
Plain Text
复制代码
1
2
3
4
5
6
7
8
9
10
11
function formatDate(date) {
var dt = date || new Date(),
year = dt.getFullYear(),
month = (dt.getMonth() + 1).toString(),
day = dt.getDate().toString();
month = month.length === 1 ? '0' + month : month;
day = day.length === 1 ? '0' + day : day;
return year + '-' + month + '-' + day;
}
// 注意点:月是从0开始计数的
Copy
5.2 如何获取一个长度一致的随机字符串?
Note
思路:使用一个长度固定的字符串,如“00000000”作为后缀,然后进行字符串截取。
Plain Text
复制代码
1
2
3
4
5
6
7
8
9
// 获取一个长度一致的字符串的随机数字
function randomStr(str) {
var random = str || Math.random();
random = random + '0000000000'; // 小技巧:防止程序报错
random = random.slice(0, 10);
return random;
}
randomStr();
Copy
5.3 写一个能遍历对象和数组通用的forEach函数
Plain Text
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function forEach(obj, fn) {
if (typeof obj === 'object') {
// 对象遍历
for (var key in obj) {
// console.log(key, obj[key]);
// 这里只去输出自己的属性,原型链上面的属性信息不用管(继承父类的属性信息是不会输出的)
if (obj.hasOwnProperty(key))
fn(key, obj[key]); // 直接执行这个函数
}
} else if (obj instanceof Array) {
// 数组遍历
obj.forEach(function (item, index) {
fn(index, item);
})
}
}
Copy
5.4 数组中常用的方法有哪些?
forEach 遍历所有的元素
every 判断所有的元素是否都符合条件
some 判断是否至少有一个元素符合条件
sort 排序
map 对数组中的元素重新组装,生成一个新的数组
filter 过滤符合条件的元素
Warning
注意点:splice,concat,sprt是直接在原地操作数组的。