由于工作项目原因,最近很少更新博客了,不过忙中抽闲,利用晚上时间,总结了一些有关JS的基础知识,并分享一些大厂面试 题,根据知识点进行具体分析讲解,希望能对方便大家来学习。
number string boolean null undefined symbol bigint
object function
数据类型结构如下图
typeof
检测出来的结果是字符串,字符串 中包含了我们对于的数据类型
typeof null 检测结果是 object ,不过null并不属于对象,而是因为二进制储存值以000开头了,检测对象细分类型,所以结果是“object”
instanceof
constructor
Object.prototype.toString.call([value])
let res = parseFloat('left:200px'); // NaN
if(res === 200) {
alert(200)
} else if (res === NaN) {
alert(NaN)
} else if(typeof res === 'number') {
alert('number') // alert输出的结果都会转换成字符串
} else {
alert('Invalid Number')
}
// number
let a = typeof typeof typeof[12, 23];
console.log(a) //string
// 解析 typeof[12, 23] => "object"
// typeof "object" => "string"
// typeof "string" => "string"
特定需要转换为Number的
隐式转换(浏览器内部默认要先转换为Number在进行计算的)
隐式转换(一般都是调用其toString)
类型一样的几个特殊点
{} == {}:false 对象比较的是堆内存的地址
[] == []:false
NaN==NaN:false
类型不一样的转换规则
null == undefined:true,但是换成 === 结果是false(因为类型不一致),剩下null/undefined和其它任何数据类型值都不相等
字符串 == 对象 要把对象转换为字符串
剩下如果== 两边数据类型不一致,都是需要转换为数字再进行比较
基于以下方式可以把其它数据类型转换为布尔
在循环或者条件判断中,条件处理的结果就是布尔类型值
let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
console.log(result); // NaNTencentnull9false
/*
* 隐式转换
true 转换为1
null 转换为0
undefined 转换为NaN
[] 转换为 ""
*/
let result2 = 10 + false + undefined + [] + 'lanfeng' + null + true + {};
// 10 + false => 10+ 0 => 10
// 10 + undefined => 10 + NaN => NaN
// NaN + [] => NaN + "" => "NaN"
// "NaN" + "lanfeng" => "NaNlanfeng"
// {} => "[object Object]"
// "NaNlanfengnulltrue[object Object]"
/*
*字符串 字符串拼接
* 对象 对象+ 0 需要把对象转换为字符串
*/
console.log([]==false);
//对象 == 布尔 都转换成数字(隐式转换),对象转换成数字:先toString转换为字符串
//(应该是先基于valueOf获取原始值,没有原始值再去toString),再转换为数字的
// 1. [] => '' => 0
// 2. false => 0
// 0 == 0
// true
console.log(![]==false); //![]优先false, false == false true
onsole.log([]===false); // false
console.log(![]==false); //true
// ![] 把数组转换成为布尔类型值后,然后取反, 为false
//false === false
// true
var a = {
i:0,
toString() {
return ++this.i
}
}
if(a==1 && a==2 && a==3) {
console.log('OK')
}
let arr = [10, 18, 0, 10, 25, 23]
arr = arr.map(parseInt)
console.log(arr)
对象变为数字,应该先valueOf,没有原始值,再toString变为字符串,最后把字符串转为数字
console.log(Number('')) // 0
console.log(Number('10')) // 10
console.log(Number('10px')) // NaN 只要出现非有效数字字符串结果都是NaN
console.log(Number(true)) // 1
console.log(Number(false)) // 0
console.log(Number(null)) // 0
console.log(Number(undefined)) // NaN
parseInt("") //NaN
Number("") // 0
isNaN("") // 转为0,0是有效数字,所以结果是false
parseInt(null) // parseInt("null") ,结果是NaN
isNaN(null) // null => 0 0是有效数字,所以结果是false
parseInt("12px") // 12
Number("12px") // NaN
isNaN("12px") // true
parseFloat("1.6px") + parseInt("1.2px") + typeof parseInt(null)
// 1.6+1+"number" => 2.6+ "number" => "2.6number"
isNaN(Number(!!Number(parseInt("0.8")))) // false
// parseInt("0.8") => 0
// !!0 => false
// Number(false) => 0
// isNaN(0) => false
typeof !parseInt(null) + !isNaN(null) // "booleantrue"
// parseInt(null) => NaN
// !NaN => true
// typeof true => "boolean"
// isNaN(null) => false
// !false => true
// => "booleantrue"
注意:
let n = "10"
console.log(++n) // 11
console.log(+n) //10
{} + 0 // 0
// 左边的{}认为是一个代码块,不参与运算,运算只处理 +0=>0
{{}+0} //
// 参与到数学运算中"[object Object]0"
0 + {} 参与到数学运算中"0[object Object]"
var a = 0;
if (true) {
a = 1;
function a() {};
a = 21;
console.log(a)
}
console.log(a);
当前上下文代码执行之前,会把var/function声明+定义,带var的只声明,带function声明+定义,如果遇到了{}新老浏览器表现还好不一致(兼容ES3、ES6)
不管{},还是一如既往的function声明+定义,而且也不会存在块级作用域
{}中的function,在全局下只声明不再定义,{} 中出现的function/let/const会创建一个块级上下文
var x = 1;
function func(x, y = function anonymous1() {x = 2}) {
x = 3;
y();
console.log(x); // 2
}
func(5);
console.log(x); // 1
var x = 1;
function func(x, y = function anonymous1() {x = 2}) {
/*
* EC(FUNC)私有上下文
* 作用域链:
* x=5 (2)
* y=anonymous1 [[scope]]:EC(FUNC)
*
* EC(BLOCK) 块级上下文 (上级上下文 EC(FUNC))
* 变量提升:var x;
* 在代码没有执行之前,我们会把EC(FUNC)中的值也给他一份 x=5 (3)
*/
var x = 3; //=>跨级上下文中的x x=3
y(); //=>不是块级的y,向上级找, EC(FUNC)
// anonymous1执行
// 私有的上下文EC(AN) 作用域链:
// x=2 修改的是EC(FUNC)中的2
console.log(x); // 3
}
func(5);
console.log(x); // 1
ES6中存在块级作用域(只要{} [除对象之外的大括号] 出现let/const/function)
有一种情况也会产生
这样在函数运行的时候,会产生两个上下文
第一个:函数执行形成的私有上下文 EC(FUNC) =>作用域链/形参赋值/…
第二个:函数体大括号包起来的是一个块级上下文 EC(BLOCK)
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function () {
console.log('wangwang');
}
Dog.prototype.sayName = function () {
console.log('my name is ' + this.name);
}
function _new(func,...args) {
//=>完成你的代码
let obj = Object.create(func.prototype)
let result = func.call(obj, ...args)
if(result !== null && /^(object | functiion)$/.test(typeof(result))) return result
return obj
}
let sanmao = _new(Dog, '三毛');
sanmao.bark(); //=>"wangwang"
sanmao.sayName(); //=>"my name is 三毛"
console.log(sanmao instanceof Dog); //=>true
// 手写call方法
~function(){
function change(context, ...args){
//=>实现你的代码
// this -> func
context = context == undefined ? window : context;
let type = typeof context;
if (!/^(object|function)$/.test(type)) {
if (/^(symbol|bigint)$/.test(type)) {
context = Object(context);
} else {
context = new context.constructor(context);
}
}
let key = Symbol('key'),
result;
context[key] = this;
result = context[key](...args);
delete context[key];
return result;
};
Function.prototype.change=change;
}();
let obj = {name:'zhufeng'};
function func(x,y){
this.total=x+y;
return this;
}
let res = func.change(obj,100,200);
//res => {name:'zhufeng',total:300}
这篇文章主要分享了javascript数据类型、数据类型转换、变量提升、闭包作用域、面向对象及一些一线面试题,如果想了解更多,请扫描二维码,关注公众号