这些JS基础知识点你真的懂了么?

378 阅读4分钟

这是我参与 8 月更文挑战的第 9 天,活动详情查看: 8月更文挑战

变量类型和计算

typeof能判断哪些类型

  • 识别所有值类型
  • 识别函数
  • 判断是否是引用类型(不可再细分)
//判断所有的值类型
typeof undefined // undefined
typeof 'abc' // string
typeof 123 // number
typeof true // boolean
typeof Symbol('sdd')  // symbol

//能判断函数
typeof console.log // function
typeof function(){} // function

//能识别引用类型(不能再细分)
typeof null // object
typeof [1,2] // object
typeof {a:123} // object
 

何时使用===,何时使用==

  • == 抽象相等,比较时,会隐式进行类型转换,再进行值比较
  • === 严格相等,会比较两个值的类型和值

值类型和引用类型的区别

  • 值类型:基本类型,Number,String,Boolean,undefined,Null(指向空指针,特殊的引用类型),Symbol,BigInt
  • 引用类型: Object,Array,Function,Date,Map,Set,WeakSet,WeakMap
区别值类型引用类型
存储位置栈中堆中(变量名在栈内存中,变量值在堆内存中)
占用空间固定不固定
赋值方式拷贝变量内容拷贝引用地址
动态属性不能添加属性可动态添加属性
检测方法typeofinstanceof

变量计算--强制类型转换

  • 字符串拼接
  • ==
    //除了 ==null  之外,其它都一律使用 === ,如
    let obj = {x:100}
    if(obj.a == null){}
    //相当于:   if(obj.a == null || obj.a == undefined){}
    
  • if语句和逻辑运算
  • 判断true/false
    //以下是falsely变量,除此之外都是truly变量
    !!0 === false
    !!NaN === false
    !!'' === false
    !!null === false
    !!undefined === false
    !!false === false
    
// 字符串拼接
var a = 100 + 10 //100
var b = 100 + '10' //10010
var c = true + '10' // true10

// == 运算符
100 == '100' //true
0 == '' //true
0 == false // true
false == '' // true
null == undefined //true
[10] == 10 // true
[] == 0 // true
[] == false // true
![] == false // true
null == false // false

//  语句
var a = true
if(a){}
var b = 100
if(b){} // 把数字转换为true
var c = ''
if(c){} // 把空字符串转换为false

// 逻辑运算
console.log(10&&0); // 0 把10转换成true
console.log('' || 'abc'); // 'abc' 把空字符串转换为false
console.log(!window.abc); // window.abc是undefined 把非undefined转换成true

//判断一个变量会被当做true还是false
var a = 100
console.log(!!a); // true

手写深拷贝

看了此文我就不信你还不懂浅拷贝、深拷贝

原型和原型链

彻底搞懂JS原型、原型链和继承

class和继承

class

  • constructor
  • 属性
  • 方法
// 类
class Student{
	constructor(name,age){
		this.name = name
		this.age = age
	}
	sayHi(){
		console.log(`姓名: ${this.name}, 年龄: ${this.age}`)
	}
}

// 通过类new 对象/实例
const pp = new Student('小鱼',18)
console.log(pp.name,pp.age) // 小鱼 18
pp.sayHi()  // 姓名: 小鱼, 年龄: 18

const cc = new Student('小C',16)
console.log(cc.name,cc.age)
cc.sayHi()

原型链.png

  • 每个class都有显示原型 prototype
  • 每个实例都有隐式原型 proto
  • 实例的 proto 指向对应的class的prototype

执行规则

  • 获取属性pp.name 或 执行方法 pp.sayHi()时
  • 先在自身属性和方法寻找
  • 如果找不到则 自动去 __proto__中查找
// class 实际上是函数,是语法糖
typeof People // function
typeof Student // function

// 隐式原型和显示原型
pp.__proto__   //隐式原型 
Student.prototype // 显示原型
pp.__proto__ === Student.prototype // true

Student.prototype.__proto__
People.prototype
People.prototype === Student.prototype.__proto__  // true

继承

  • extends
  • super (父类)
  • 扩展和重写
// 父类
class People{
	constructor(name){
		this.name =name
	}
	eat(){
		console.log(`${this.name} eat something`)
	}
}
// 子类
class Student extends People{
	constructor(name,age){
		super(name)
		this.age = age
	}
	sayHi(){
		console.log(`姓名: ${this.name}, 年龄: ${this.age}`)
	}
}
// 子类
class Teacher extends People{
	constructor(name,major){
		super(name)
		this.major = major
	}
	teach(){
		console.log(`${this.name} 教授 ${this.major}`)
	}
}

const pp = new Student('小鱼',18)
console.log(pp.name,pp.age) // 小鱼 18
pp.sayHi()  //姓名: 小鱼, 年龄: 18
pp.eat() // 小鱼 eat something
//实例
const lu = new Teacher('陆老师','语文')
console.log(lu.name,lu.major) // 陆老师 语文
lu.teach()  // 陆老师 教授 语文
pp.eat() // 陆老师 eat something

instanceof

// 参照上面继承
pp instanceof Student // true
pp instanceof People // true
pp instanceof Object //true

[] instanceof Array // true
[] instanceof Object // true

{} instanceof Object // true

题目

如何判断数组

  1. Object.prototype.toString.call()
  2. Array.isArrray()
  3. instanceof: 判断一个变量是否某个对象的实例
  4. Array.prototype.isPrototypeOf: 利用isPrototypeOf()方法,判定Array是不是在obj的原型链中
  5. constructor: 返回对创建此对象的数组函数的引用,就是返回对象相对应的构造函数
function isArray(obj){
  // return Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
  return Object.prototype.toString.call(obj) === '[object Array]';
}
function isArray(obj){
  return  Array.isArrray(obj);
}
function isArray(obj){
  return obj instanceof Array
}
function isArray(obj){
  return obj.constructor === Array
}
function isArray(obj){
  return Array.prototype.isPrototypeOf(obj)
}

手写jquery

class jQuery{
	constructor(selector){
		const result = document.querySelectorAll(selector)
		const length = result.length
		for(let i=0; i<length;i++){
			this[i] = result[i]
		}
		this.length = length
		this.selector = selector
	}
	get(index){
		return this[index]
	}
	each(fn){
		for(let i=0; i<this.length;i++){
			const elem = this[i]
			fn(elem)
		}
	}
	on(type,fn){
		return this.each(elem=>{
			elem.addEventListener(type,fn,false)	
		})
	}
	//扩展很多DOM API
}

// 插件
jQuery.prototype.dialog = function(info){
	alert(info)
}
//造轮子
class myJQuery extends jQuery{
	constructor(selector){
		super(selector)
	}
	//扩展自己的方法
	addClass(className){

	}
}

//调用demo
const $p = new jQuery('p')
$p.get(1)
$p.each(elem=>console.log(elem.nodeName))
$p.on('click',()=>alert('clicked'))
$p.dialog('test')

作用域和闭包

作用域

  • 全局作用域
  • 函数作用域
  • 块级作用域

自由变量

  • 一个变量在当前作用域没有定义,但被使用了
  • 向上级作用域,一层一层依次寻找,直到找到为止
  • 如果到全局作用域都没有找到,则报错 XX is not defined

闭包 作用域应用的特殊情况,有2种表现:

  • 函数作为参数被传递
  • 函数作为返回值被返回

自由变量的查找: 是在函数定义的地方,向上级作用域查找; 不是在执行的地方!!!

//函数作为返回值
function create(){
	let a = 100
	return function(){
		console.log(a)
	}
}
const fn = create()
let a = 200
fn()  // 100

//函数作为参数
function print(fn){
	let a = 200
	fn()
}
let a = 100
function fn(){
	console.log(a)
}
print(fn) //100

this在不同场景,如何取值

this取值,是在函数执行的时候确认,不是在函数定义时确认

  • 作为普通函数
  • 使用 call apply bind
  • 作为对象方法调用
  • 在class方法中调用
  • 箭头函数
function fn1(){
	console.log(this)
}
fn1() // window

fn1.call({x:100}) // {x:100}

let fn2 = fn1.bind(x:200)
fn2() // {x:200}

const pp = {
	name:'pp',
	sayHi(){
		//this 即当前对象
		console.log(this)
	},
	wait(){
		setTimeout(function(){
			// this === window
			console.log(this)
		})
	},
	wait2(){
		setTimeout(() => {
			// this 即当前对象
			console.log(this)
		})
	}
}

class People{
	constructor(name){
		this.name = name
	}
	sayHi(){
		console.log(this)
	}
}
const pp = new People('小玉儿')
pp.sayHi() // 指向 pp对象

手写bind函数

function fn1(a,b,c){
	console.log('this',this) // this { x:100}
	console.log(a,b,c)  // 10 20 30
	return 'this is fn1'
}
const fn2 = fn1.bind({x:100},10,20,30)
const res = fn2()
console.log(res) // this is fn1

//模拟bind
Function.prototype.bind1 = function(){
	//将参数拆解为数组
	const args = Array.prototype.slice.call(arguments)

	//获取 this(数组第一项)
	const t = args.shift()
 	
 	//fn1.bind(...)中的fn1
	const self = this

	//返回一个函数
	return function(){
		return self.apply(t,args)
	}
}

实际开发中闭包应用场景

  • 隐藏数据
// 闭包隐藏数据,只提供API
function createCache(){
	const data = {} // 闭包中的数据,被隐藏,不被外界访问
	return {
		set: function(key,value){
			data[key] = value 
		},
		get: function(key){
			return data[key]
		}
	}
}
const a = createCache()
a.set('a1',100)
console.log(a.get(a1))