菜鸡打卡
JavasSript 基础
1.js 中有哪些数据类型
nuumber( 数 值 ), string( 字 符 串 ), boolean( 布 尔 ), null( 空 ),undefined(未定义), object(对象),ES6 Symbol,bigInt
2.typeof(typeof()) 和 instanceof 的区别
typeof 可以判断变量的数据类型,返回值是字符串。
a instanceof b 是判断 b 是不是在 a 的原型链上, 也可以实现判断数据类型, 返回值为布尔.
3.怎么判断两个对象相等?
先判断俩者是不是对象;
再判断俩个对象的所有 key 值是否相等相同
最后判断俩个对象的相应的 key 对应的值是否相同
4.列举和数组操作相关的方法
-
push:将元素添加到数组的末尾, 返回值是数组长度
-
pop:将数组最后一个元素弹出, 返回值是被弹出的元素
-
unshift:在数组的开头插入一个元素,返回值是数组的长度
-
shift:将数组第一个元素弹出,返回值是被弹出的元素
-
splice(index,len):删除数组中指定元素
-
concat:连接数组
-
reverse: 翻转数组
5.列举和字符串操相关的方法
-
substr(start,len)/substring(start,end): 截取字符串
-
slice:从数组会字符串中截取一段
-
indexOf/lastIndexOf:查找某一个字符是否存在于另外一个字符串中, 存在则返回索引, 不存在则返回-1;indexOf 是从前向后顺序查找;
-
lastIndexOf:是从后向前查找
-
replace:替换字符串特定的字符
-
toUpperCase:将字符串转成大写
-
toLowerCase:将字符串转成小写
-
charAt:获取字符串中指定索引的字符
6.分别阐述 split(),slice(),splice(),join()?
-
split 可以使用一个字符串切割另外一个字符串, 返回值是数组;
-
slice 可以从数组中截取一部分(字符串对象也有 slice 方法)
-
splice(index,len)可以删除指定的数组元素
-
join 可以将数组元素使用特定的连接符拼接成字符串
7.如何判断一个变量 foo 是数组?
foo instanceof Array;
foo.constructor === Array;
Array.isArray(foo)
Object.prototype.toString.call(foo) === "[object Array]"
8.什么是原型对象?
每一个构造函数都有一个 prototype 属性,这个属性的值是一个对象,这个对象就叫做构造函数的原型对象.
一般建议将构造函数的成员属性绑定在原型对象 protoptype 上,因为原型对象 prototype 身上的属性默认可以通过实例对象访问到.
这样做可以保证在每次通过 new 关键字创建对象的时候,这些方法不会被重复在内存中创建.
9.什么是原型链?
每个构造函数都有一个 prototype 属性,即原型对象,通过实例对象的 proto 属性也可访问原型对象;而原型对象本质也是一个对象, 是对象就有自己的原型对象, 最终形成的链状的结构称为原型链.
10.什么是构造函数?
构造函数有本质也是一个函数,只不过这个函数在定义的时候的首字母一般需要大写,构造函数调用的时候必须通过一个 new 关键字来调用;一般不直接使用构造函数,二十使用构造函数创建出来的实例对象。构造函数是 js 面向对象的一个重要组成部分。
11.js 中实现继承的方式?
ES6 之前官方并没有提供一种实现继承的语法, 所以大部分继承方式
都是程序员通过代码在模拟.常见的继承方式有以下几种:
- 原型继承
- 借用构造函数继承
- 组合继承
function Person(name, age, gender) {
this.name = name || '';
this.age = age || '';
this.gender = gender || '';
}
Person.prototype.sayHi = function () {
console.log('I am ' + this.name);
}
function Student(name, age, gender, score) {
// 通过构造继承属性
Person.call(this, name, age, gender);
}
// 通过原型继承,继承方法
Student.prototype = new Person();
// 修改 constructor 的指向
Student.prototype.constructor = Student;
// 动态添加成员方法
Student.prototype.printScore = function () {
console.log('my score is ' + this.score);
}
// 创建 Student 实例对象
let s1 = new Student('mint', 18, '男', 100);
s1.sayHi();
s1.printScore();
ES6 之后使用 extends 关键字实现继承(class Student extends Person{})
12.什么是闭包, 有什么作用, 使用的时候需要注意什么?
闭包是一个跟函数有关的概念,表现形式是一个夫函数内部,嵌套了一个子函数,子函数直接或间接的返回给外部作用域,并且子函数会用到父函数局部作用域中的变量。当在外部调用这个子函数的时候,就会发生闭包现象。
闭包的作用:闭包可以延展一个函数的作用域
注意事项:不能滥用闭包,会导致内存泄漏
function fn() {
var a = 100;
return function () {
return console.log(a);
}
}
var fn1 = fn();
fn1();
13.什么是内存泄漏, 那些操作会引起内存泄漏?
内存泄漏是指本应该被垃圾回收机制回收的内存空间由于某种特殊原因没有及时被回收, 称之为内存泄漏. 滥用全局变量和滥用闭包都会导致内存泄漏.
14.什么是预解析?
JS 代码在执行之前,解析引擎会对代码进行一个预先的检查, 主要会对变量和函数的声明进行提升, 将变量和函数的声明提到代码的最前面.变量只提升声明, 不提升赋值.
15.说说你对 this 关键字的理解
this 在不同的场景下指向不太一样, 主要分为一下几种情况:
-
普通函数中指向全局 window
-
对象的成员方法中指向该方法的宿主对象;
-
构造函数中指向 new 出来的实例对象
-
事件处理函数中指向事件源
-
回调函数中指向全局 window
16. call/apply/bind 的区别
这三个方法都是函数这个特殊对象的方法,通过这三个方法都可以改变函数内部 this 的指向.
不同点:
call 和apply 会调用一次函数, 而 bind 不会调用函数, 只会在内存中创建一个函数的副本(修改过 this 指向的函数)
call 从第二个参数开始需要一个参数列表
apply 第二个参数需要是一个数组
17.new 操作符具体干了什么呢?
第一步创建一个空对象;
第二步将 this 指向空对象;
第三步动态给刚创建的对象添加成员属性;
第四步隐式返回 this.
18.下面代码的执行结果是什么?
(function () {
console.log('hello one');
setTimeout(function (){
console.log('hello two');
}, 100);
setTimeout(function () {
console.log('hello three');
}, 0)
console.log('hello four');
})();
依次输出: hello one,hello four,hello three,hello two
19.下面代码执行结果是什么?
var a={
id:10
}
b=a;
b.id=1;
b.name='test';
console.log(a);
执行结果: 输出 {id: 1, name: "test"}
分析过程:
对象是一种引用数据类型, 简单的 b=a 只是把 a 在内存中的地址赋值给了 b, 所以修改 b 会影响 a
20.下面的代码会输出什么? 怎么改动下面代码, 使其依次输出1,2,3,4,5
for (var i=1;i<=5;i++) {
setTimeout(function () {
console.log(i)
},1000)
}
执行结果:在控制台输出:6,6,6,6,6
改造后的代码:
for (var i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, 1000 * i)
})(i)
}
执行结果:在控制台输出:1,2,3,4,5