JS知识点总结(一)


前言

针对JavaScript初级、高级相关知识点,以及ES6的新特性等面试常考的内容进行深入的总结

1.JavaScript 的基本类型有哪些?引用类型有哪些?null和undefined 的区别?

数据类型:

基本数据类型:Number、String、Boolean、null、undefined
引用数据类型:Function、Object、Array

区别

undefined:表示变量声明但未初始化时的值

null:表示准备用来保存对象,还没有真正保存对象的值。从逻辑角度看,null 值表示一个空对象指针

ECMA 标准要求 null 和 undefined 等值判断返回 true

null == undefined // true

null === undefined // false

2.如何判断JS中的数据类型

typeof

typeof 可以用来区分除了 null 类型以外的原始数据类型,对象类型的可以从普通对象里面识别出函数:

console.log(typeof 1);               // number
console.log(typeof true);            // boolean
console.log(typeof 'mc');            // string
console.log(typeof Symbol())           // symbol
console.log(typeof function(){});    // function
console.log(typeof console.log());   // function
console.log(typeof []);              // object 
console.log(typeof {});              // object
console.log(typeof null);            // object
console.log(typeof undefined);       // undefined
console.log(typeof Object);          //function
console.log(typeof Array())            //object

instanceof

不能用于判断原始数据类型的数据

console.log(1 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false  
console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true

优点: 能够区分Array、Object和Function,适合用于判断自定义的类实例对象。instanceof运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的prototype属性。
缺点: Number,Boolean,String基本数据类型不能判断,同时Function、Array和Object还是不能判断其具体的数据类型

constructor

console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true

constructor有两个作用,一是判断数据的类型(Number、String、Boolean、Array、Function、Object),二是对象实例通过 constrcutor 对象访问它的构造函数。

Object.prototype.toString.call()

var toString = Object.prototype.toString;
console.log(toString.call(1));                      //[object Number]
console.log(toString.call(true));                   //[object Boolean]
console.log(toString.call('mc'));                   //[object String]
console.log(toString.call([]));                     //[object Array]
console.log(toString.call({}));                     //[object Object]
console.log(toString.call(function(){}));           //[object Function]
console.log(toString.call(undefined));              //[object Undefined]
console.log(toString.call(null));                   //[object Null]

如何判断数组的基本数据类型

  • 通过Object.prototype.toString.call()做判断
  • 通过ES6的Array.isArray()做判断
Array.isArrray(obj);
  • 通过instanceof做判断;
  • 通过Array.prototype.isPrototypeOf

3.创建函数的几种方式

//函数声明
function sum1(num1,num2){
   return num1 + num2
}
//函数表达式
var sum2 = function(num1,num2){
   return num1+num2
}

4 JS创建对象的几种方式

  • 使用对象字面量的方式创建{}
var Cat = {}; //JSON 
Cat.name="kity"; //添加属性并赋值
Cat.age=2; 
Cat.sayHello=function(){ 
alert("hello "+Cat.name+",今年"+Cat["age"]+"岁了"); 
//可以使用“.”的方式访问属性, 也可以使用 HashMap 的方式访问
}
Cat.sayHello(); //调用对象的(方法)函数
  • 用function函数来模拟class
    创建一个对象,相当于 new 一个类的实例(无参构造函数)

代码如下

function Person(){ 
}
var personOne=new Person(); //定义一个 function,如果有 new 关键字去"实例化",那么该 function 可以看作是一个类
personOne.name="dylan"; 
personOne.hobby="coding"; 
personOne.work=function(){ 
alert(personOne.name+" is coding now..."); 
}
personOne.work(); 

可以使用有参构造函数来实现,这样定义更方便,扩展性更方便

function Pet(name,age,hobby){
this.name  = name;
this.hobby = hobby;
this.eat = function(){
alert("我叫"+this.name+",我喜欢"+this.hobby+",也是个吃货"); 
}
}

使用工厂方式创建Object关键字

var wcDog = new Object(); 
wcDog.name="旺财"; 
wcDog.age=3; 
wcDog.work=function(){ 
alert("我是"+wcDog.name+",汪汪汪......"); 
}
wcDog.work();
  • 使用原型对象的方式 prototype 关键字
function Dog(){ 
}
Dog.prototype.name ="旺财"; 
Dog.prototype.eat = function(){ 
alert(this.name + "是个吃货"); 
}
var wangcai = new Dog(); 
wangcai.eat(); 
  • 混合模式(原型和构造函数) :
function Car(name,price){ 
this.name=name; 
this.price=price; 
}
Car.prototype.sell=function(){ 
alert("我是"+this.name+",我现在卖"+this.price+"万元"); 
} 
var camry = new Car("凯美瑞",27); 
camry.sell(); 

5.请分别指出= =和= = =的区别

= = =:三个等号称为等同符,当等号两边的值为相同类型的时候,直接比较等号两边 的值,值相同则返回 true,若等号两边的值类型不同时直接返回 false。也就是说三个等号 既
要判断值也要判断类型是否相等
= =:两个等号称为等值符,当等号两边的值为相同类型时比较值是否相同,类型不同时会发生类型的自动转换,转换为相同的类型后再作比较。也就是说两个等号只要值相等就可以

6.null与undefined的区别

典型用法是:

1、变量被声明了,但没有赋值时,就等于 undefined
2、调用函数时,应该提供的参数没有提供,该参数等于 undefined
3、对象没有赋值的属性,该属性的值为 undefined
4、函数没有返回值时,默认返回 undefined
null 表示"没有对象",即该处不应该有值。典型用法是:
4.1) 作为函数的参数,表示该函数的参数不是对象
4.2) 作为对象原型链的终点

7.区分数组和对象的方法

方法一:通过 ES6 中的 Array.isArray 来识别

Array.isArray([]) //true

Array.isArray({}) //false

方法二:通过 instanceof 来识别

[] instanceof Array //true

{} instanceof Array //false

方法三:通过调用 constructor 来识别

{}.constructor //返回 object

[].constructor //返回 Array

方法四:通过 Object.prototype.toString.call 方法来识别

Object.prototype.toString.call([]) //["object Array"]

Object.prototype.toString.call({}) //["object Object"]

8.多维数组降维的几种方法

(1)数组字符串化

let arr = [[222, 333, 444], [55, 66, 77] ]
arr += '';
arr = arr.split(',');
console.log(arr); // ["222", "333", "444", "55", "66", "77"]

(2) Array.prototype.flat()

var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]

9.怎么判断两个对象是否相等?

想要比较两个对象内容是否一致,思路是要遍历对象的所有键名和键值是否都一致:

1、判断两个对象是否指向同一内存

2、使用 Object.getOwnPropertyNames 获取对象所有键名数组

3、判断两个对象的键名数组是否相等

4、遍历键名,判断键值是否都相等

10.列举三种强制类型转换和两种隐式类型转换?

  • 强制
    转化成字符串 toString() String()
    转换成数字 Number()、 parseInt()、 parseFloat()
    转换成布尔类型 Boolean()
  • 隐式
    拼接字符串
    例子 var str = “” + 18
    - * / % ==

11.JS中怎么获取当前日期的月份?

JavaScript 中获得当前日期是使用 new Date 这个内置对象的实例,其他一些进阶的操作
也是基于这个内置对象的实例。
获取完整的日期(默认格式):
var date = new Date(); // Sat Jul 06 2019 19:59:27 GMT+0800 (中国标准时间)
获取当前年份:
var year = date.getFullYear(); // 2019
获取当前月份:
var month = date.getMonth() + 1; // 7
获取当前日:
var day = date.getDay(); // 6
获取当前日期(年--日):
month = (month > 9) ? month : ("0" + month);
day = (day < 10) ? ("0" + day) : day;
var today = year + "-" + month + "-" + day; // 2019-07-06
另外的一些操作:
date.getYear(); // 获取当前年份(2 位)
date.getFullYear(); // 获取完整的年份(4 位, 1970-????)
date.getMonth(); // 获取当前月份(0-11,0 代表 1 月)
date.getDate(); // 获取当前日(1-31)
date.getDay(); // 获取当前星期 X(0-6,0 代表星期天)
date.getTime(); // 获取当前时间(从 1970.1.1 开始的毫秒数)
date.getHours(); // 获取当前小时数(0-23)
date.getMinutes(); // 获取当前分钟数(0-59)
date.getSeconds(); // 获取当前秒数(0-59)
date.getMilliseconds(); // 获取当前毫秒数(0-999)
date.toLocaleDateString(); // 获取当前日期
date.toLocaleTimeString(); // 获取当前时间
date.toLocaleString( ); // 获取日期与时间

12.什么是类数组(伪数组),如何将其转化为真实的数组

1、具有 length 属性
2、按索引方式存储数据
3、不具有数组的 push.pop 等方法
伪数组(类数组):无法直接调用数组方法或期望 length 属性有什么特殊的行为,不具有数组的 push.pop 等方法,但仍可以对真正数据遍历方法来遍历它们。典型的是函数document.childnodes之类的,它们返回的 nodeList 对象都属于伪数组

1.使用 Arrray.from()--ES6
2.[].slice.call(eleArr) 或则 Array.prototype.slice.call(eleArr)
示例:
let eleArr = document.querySelectorAll('li');
Array.from(eleArr).forEach(function(item){
alert(item);
});
let eleArr = document.querySelectorAll('li');
[].slice.call(eleArr).forEach(function(item){
alert(item);
});

13.JavaScript 中的作用域、预解析与变量声明提升?

就是变量的有效范围。 在一定的空间里可以对数据进行读写操作,这个空间就是数据的作用域

1、全局作用域: 最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的;

2、局部作用域: 局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的,最常见的例如函数内部。在 ES6 之前,只有函数可以划分变量的作用域,所以
在函数的外面无法访问函数内的变量

3、块级作用域:凡是代码块就可以划分变量的作用域,这种作用域的规则就叫块级作用域块级作用域 函数作用域 词法作用域之间的区别:
3.1)块级作用域和函数作用域描述的是,什么东西可以划分变量的作用域

3.2)词法作用域描述的是,变量的查找规则

JavaScript 代码的执行是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器执 行 JavaScript 代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:

1.把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值

2.把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用

3.先提升 function,在提升 var

变量提升

变量提升:定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升

函数提升:JavaScript 解析器首先会把当前作用域的函数声明提前到整个作用域的最前面,但不会发生函数的调用

14 .函数提升与变量提升的区别

变量提升

简单说就是在 JavaScript 代码执行前引擎会先进行预编译,预编译期间会将变量声明与函 数声明提升至其对应作用域的最顶端,函数内声明的变量只会提升至该函数作用域最顶层
当函数内部定义的一个变量与外部相同时,那么函数体内的这个变量就会被上升到最顶端

举例来说:
console.log(a); // undefined

var a = 3;

// 预编译后的代码结构可以看做如下运行顺序

var a; // 将变量 a 的声明提升至最顶端,赋值逻辑不提升。

console.log(a); // undefined

a = 3; // 代码执行到原位置即执行原赋值逻辑

函数提升

函数提升只会提升函数声明式写法,函数表达式的写法不存在函数提升
函数提升的优先级大于变量提升的优先级,即函数提升在变量提升之上

15.什么是作用域链?

作用域链

在当前作用域中查找所需变量,但是该作用域没有这个变量,那这个变量就是自由变量。如果在自己作用域找不到该变量就去父级作用域查找,依次向上级作用域查找,直到访问到window对象就被终止,这一层层的关系就是作用域链。

作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,可以访问到外层环境的变量和函数。

作用域链的本质上是一个指向变量对象的指针列表。变量对象是一个包含了执行环境中所有变量和函数的对象。作用域链的前端始终都是当前执行上下文的变量对象。全局执行上下文的变量对象(也就是全局对象)始终是作用域链的最后一个对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值