夯实基础,完全掌握js的核心技术(一)

因为工做项目缘由,最近不多更新博客了,不过忙中抽闲,利用晚上时间,总结了一些有关JS的基础知识,并分享一些大厂面试 题,根据知识点进行具体分析讲解,但愿能对方便你们来学习。 javascript

数据类型/堆栈内存

JS中的数据类型

  1. 基本数据类型

number string boolean null undefined symbol bigintjava

  1. 引用数据类型

object function
数据类型结构以下图 面试

image.png

数字类型中的比较奇怪的值

  1. NaN是number类型
    Console.log(typeof NaN) // number
    Console.log(NaN === NaN)
    object.is(NaN, NaN) // true
  2. 检测一个值是否为有效数字 isNaN
    Console.log(isNaN(10)) // false
    console.log(isNaN(‘AA’)) // 在检测的时候,若是当前这个值不是数字类型,先隐士转换为数字类型(Number),而后再检测是否为非有效数字 true
  3. Infinity无穷大的值

数据类型转换方法

  1. typeof数组

    检测出来的结果是字符串,字符串 中包含了咱们对于的数据类型
    typeof  null 检测结果是 object ,不过null并不属于对象,而是由于二进制储存值以000开头了,检测对象细分类型,因此结果是“object”
    浏览器

  2. instanceof闭包

  3. constructor函数

  4. 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"

复制代码

数据类型转换的4大核心标准

  1. 把其余数据类型转换为Number类型
  • 特定须要转换为Number的

+ Number([val])
   + parseInt/parseFloat([val])ui

  • 隐式转换(浏览器内部默认要先转换为Number在进行计算的)
  • isNaN([val]) 
    + 数学运算(特殊状况:+在出现字符串的状况下不是数学运算,是字符串拼接)
    + 在==比较的时候,有些值须要转换为数字再进行比较
  1. 把其它数据类型转换为字符串
  • 能使用的办法
  • toString()
    + String()
  • 隐式转换(通常都是调用其toString)

+ 加号运算的时候,若是某一边出现字符串,则是字符串拼接
+ 把对象转换为数字,须要先toString()转换为字符串,再去转换为数字
+ 基于alert/confirm/prompt/document.write...这些方式输出内容,都是把内容先转换为字符串,而后再输出的
this

  1. 在==比较的过程当中,数据转换的规则
  • 类型同样的几个特殊点

{}=={}:false  对象比较的是堆内存的地址
     []==[]:false
NaN==NaN:false

  • 类型不同的转换规则

null==undefined:true,可是换成===结果是false(由于类型不一致),剩下null/undefined和其它任何数据类型值都不相等
字符串==对象  要把对象转换为字符串
  剩下若是==两边数据类型不一致,都是须要转换为数字再进行比较

  1. 把其它数据类型转换为布尔
  • 基于如下方式能够把其它数据类型转换为布尔

+ ! 转换为布尔值后取反
     + !! 转换为布尔类
+ Boolean([val])

  • 在循环或者条件判断中,条件处理的结果就是布尔类型值
  • 在循环或者条件判断中,条件处理的结果就是布尔类型值
    注意:规则:只有 ‘0、NaN、null、undefined、空字符串’ 五个值会变为布尔的FALSE,其他都是TRUE
    把其余类型转换为字符串,通常都是直接“”包起来,只有{}普通对象调取toString是调取的Object.prrototype.toString,不是转换为字符串,而是检测数据类型,返回结果是"[object Objecg]"
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)
复制代码

把其余类型转换为数字

  1. Number机制

对象变为数字,应该先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
复制代码
  1. parseInt机制,从字符串左侧第一个字符开始,查找有效数字字符(遇到非有效数字字符中止查找,不论后面是否还有数字字符,都再也不找了),把找到的有效数字字符转为数字,若是一个都没找到结果返回NaN(parseFloat比它多识别一个小数点)
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"
复制代码

注意:

  1. 在js 中加号左右两边出现字符串,则变为字符串拼接(有特殊性),若是出现对象也会变为字符串拼接(由于本来应该是把对象转为数字,可是对象转数字须要先转换为字符串,则+遇到字符串直接转变为字符串拼接)
  2. 加号即便一边出现字符串或者对象,也不必定是字符串拼接:++i/i++/+i,这种状况是数学运算
let n = "10"
console.log(++n) // 11
console.log(+n) //10
{} + 0 // 0
// 左边的{}认为是一个代码块,不参与运算,运算只处理 +0=>0
{{}+0} // 
// 参与到数学运算中"[object Object]0"
0 + {}  参与到数学运算中"0[object Object]"

复制代码


**

image.png

变量提高问题

var a = 0;
if (true) {
    a = 1;
    function a() {};
    a = 21;
    console.log(a)
}
console.log(a);
复制代码

当前上下文代码执行以前,会把var/function声明+定义,带var的只声明,带function声明+定义,若是遇到了{}新老浏览器表现还好不一致(兼容ES三、ES6)

  • IE浏览器 <= IE10

无论{},仍是一如既往的function声明+定义,并且也不会存在块级做用域

  • 新版本浏览器

{}中的function,在全局下只声明再也不定义,{} 中出现的function/let/const会建立一个块级上下文

image.png

闭包做用域

var x = 1;
function func(x, y = function anonymous1() {x = 2}) {
    x = 3;
    y();
    console.log(x); // 2
}
func(5);
console.log(x); // 1

复制代码

image.png

var x = 1;
function func(x, y = function anonymous1() {x = 2}) {
   /* * EC(FUNC)私有上下文 * 做用域链:<EC(FUNC),EC(G)> * 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) 做用域链:<EC(AN),EC(FUNC)>
    // 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数据类型、数据类型转换、变量提高、闭包做用域、面向对象及一些一线面试题,若是想了解更多,请扫描二维码,关注公众号

qrcode_for_gh_4d3763fa9780_258 (1).jpg
相关文章
相关标签/搜索