JavaScript 基础知识

128 阅读7分钟

一、变量类型和计算 1、JS中使用typeof能得到哪些类型 —— typeof只能区分值类型和function

2、何时使用 === 何时使用 ==
	—— 字符串拼接时发生“类型转换”
	—— 双等和全等计算的时候会发生“类型转换” 100 == ‘100‘
	—— if语句
	—— 逻辑运算符

	if (obj.a == null) { // 这里相当于obj.a === null || obj.a === undefined 的简写形式
		// 上面的判断条件是jquery源码中推荐写法
	}

3JS中有哪些内置函数
	—— ObjectArrayBooleanNumberStringFunctionDateRegExpError

4JS按照存储方式应该分为哪些类型
	—— 值类型
	—— 引用类型:为了节省内存空间

5、如何理解JSON
	—— JSON是一个JS对象,JSON有两个APIJSON.stringifyJSON.parse

二、原型、原型链 —— 知识点: 1、构造函数 function Foo (name, age) { this.name = name this.age = age // return this 默认有这一行 } var f = new Foo('张三', 22)

	2、构造函数 —— 扩展
		—— var a = {} 其实是var a = new Object()的语法糖
		—— var a = [] 其实是var a = new Array()的语法糖
		—— function Foo(){} 其实是 var Foo = new Function()的语法糖
		—— 使用instanceof判断一个函数是否是一个变量的构造函数

	3、原型规则和示例
		—— 所有的引用类型(数组、对象、函数),都具有对象特性,即可以自由扩展属性(除了‘null之外’)
		—— 所有的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通对象
		—— 所有函数(只指function函数),都有一个prototype属性,属性值也是一个普通对象。
		—— 所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的‘prototype’属性值
		—— 当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找。

		var obj = {}; obj.a = 100;
		var array = []; arr.a = 100;
		funcion fn() {}; fn.a = 100;

		console.log(obj.__proto__)
		console.log(array.__proto__)
		console.log(fn.__proto__)

		console.log(obj.__ptoto__ === Object.prototype)

		—— 通过hasOwnProperty()能判断对象自身属性,而不是继承的属性,


	4、原型链
		—— f ——__proto__ ——> Foo.prototype ——__proto__ ——> Obejct.prototype ——__proto__——> null


	5instanceof
		—— 用于判断引用类型属于哪个构造函数的方法:instanceof

—— 面试题:
	1、如何准确判断一个变量是数组类型
		var arr = []
		arr typeof Array  // true

	2、写一个原型链继承的例子
		—— 封装一个DOM查询
			function Elem(id) {
				this.ele = document.getElementById(id)
			}
			Elem.prototype.html=function(val) {
				var elem = this.elem
				if (val) {
					elem.innerHTML = val 
					return this
				} else {
					return elem.innerHTML
				}
			}
			Elem.prototype.on = function(type, fn){
				var elem = this.elem
				elem.addEventListener(type, fn)
				return this
			}
			var div1 = new Elem('div1')
			div1.html('<p>hello</p>').on('click', function(){alert('hello')}).html('<p>Word</p>').on('click', function(){alert('Word')})

	3、描述new一个对象的过程
		—— 创建一个新对象
		—— this指向这个新对象
		—— 执行代码,即对this赋值
		—— 返回this

	4、zepto(或其他框架)源码中如何使用原型链
		—— zepto设计和源码分析【慕课网】

三、作用域、闭包

—— 知识点
	1、执行上下文
		—— 范围:一段<script>或一个函数
		—— 全局【<script>则生成一个全局的执行上下文】:变量定义、函数声明
		—— 函数【函数则生成一个函数的执行上下文】:变量定义、函数声明、thisarguments
		PS:注意“函数声明”和“函数表达式”的区别

	2this
		—— this要在执行的时候才能确认值,定义时无法确认。
			var a = {
				name: 'A',
				fn: function() {
					console.log(this.name)
				}
			}
			a.fn() // this === a
			a.fn.call({name: 'B'}) // this === {name: 'B'}
			var fn1 = a.fn
			fn1() // this === window

		—— 场景
			1、作为构造函数执行
			2、作为对象属性执行
			3、作为普通函数执行  【thiswindow4、call、apply、bind

	3、作用域
		—— 示例:
			if(true){
				var name = 'zhangsan'
			}
			console.log(name) // zhangsan

			eg: 写法不同功能同上 【这个是推荐写法】
			var name
			if(true){
				var name = 'zhangsan'
			}
			console.log(name) // zhangsan


	4、作用域链
		—— 示例:
			var a = 100;
			var FA = function() {
				var b = 200
				var FB = function() {
					var c = 300
					console.log(a)
					console.log(b)
					console.log(c)
				}
				FB()
			};
			FA();

	5、闭包
		—— 示例:一个函数的作用域是它定义时的作用域
			var Fn = function() {
				var a = 200
				return function() {
					console.log(a) // 自由变量,父作用域寻找
				}
			}
			var fn1 = Fn()
			var a = 300
			fn1() // 100

		—— 闭包的使用场景
			1、函数作为返回值
			2、函数作为参数传递

		—— 代码演示
			var Fn = function() {
				var a = 200
				return function() {
					console.log(a) // 自由变量,父作用域寻找
				}
			}
			var fn1 = Fn()
			var fn2 = function(fn) {
				var a = 500
				fn()
			}
			fn2(fn1) // 100, 闭包函数的父作用域在声明的地方查找

—— 题目
	1、说下对变量提升的理解
		—— 变量的定义
		—— 函数的声明(注意和函数表达式的区别)

	2、说明this几种不同的使用场景
		—— 作为构造函数执行
		—— 作为对象属性执行
		—— 作为普通函数执行  【thiswindow】
		—— call、apply、bind

	3、创建10个<a>标签,点击的时候弹出对应的序号
			for (var i = 0; i < 10; i++) {
				(function(i){
					var a = document.createElement('a')
					a.innerHTML = i + '<br/>'
					a.addEventListener('click', function(e) {
						e.preventDefault()
						alert(i)
					})
					document.body.appendChild(a)
				})(i)
			}

	4、如何理解作用域
		—— 自由变量
		—— 作用域链,即自由变量的查找
		—— 闭包的两个场景

	5、实际开发中闭包的应用
		—— 封装变量收敛权限
			function isFirstLoad() {
				var _list = [];
				return function(id) {
					if (_list.indexof(id) >=0) {
						return false
					} else {
						_list.push(id)
						return true
					}
				}
			}
			// 使用:
			var firstLoad = isFirstLoad()
			firstLoad(10) // true
			firstLoad(10) // false
			firstLoad(20) // true

			// 你在 isFirstLoad 函数外面,根本不可能修改 _list 的值

四、异步、单线程 —— 知识点 1、什么是异步(对比同步) —— 示例: 异步:不会阻塞后边的代码执行 console.log(100) setTimeout(function() {console.log(200)}, 1000) console.log(300)

			同步:阻塞后边的代码执行
			console.log(100)
			alert(200)
			console.log(300)

		—— 何时需要异步
			1、在可能发生等待的情况
			2、等待的过程中不能像alert一样,阻塞程序的运行
			3、因此,所有的“等待情况”,都需要异步

	2、前端使用异步的场景
		—— 定时任务: setTimeoutsetInterval
		—— 网络请求:ajax请求、动态<img>加载
		—— 事件绑定

		—— 示例:
			// <img>加载
			console.log('start')
			var img = document.createElement('img');
			img.onload = function () {
				console.log('loaded')
			}
			img.src = './XXX.png'
			console.log('end')

			// 绑定事件
			console.log('start')
			document.getElementById('btn1').addEventListener('click', function(){
				alert('click');
			})
			console.log('end')

	3、异步和单线程
		—— 单线程:一次只能干一个事儿


—— 题目
	1、同步和异步的区别是什么?分别举一个同步和异步的例子
		—— 同步会阻塞代码执行,而异步不会
		—— alert是同步,setTTimeout是异步

	2、一个关于setTimeout的笔试题
		console.log(1)
		setTimeout(function(){console.log(2)},0)
		console.log(3)
		setTimeout(function(){console.log(4)}, 1000)
		console.log(5)

	3、前端使用异步的场景有哪些?
		—— 定时任务: setTimeoutsetInterval
		—— 网络请求:ajax请求、动态<img>加载
		—— 事件绑定

五、补充

—— 知识点
	1、日期
		Date.now()
		var dt = new Date()
		dt.getTime()	 // 获取毫秒数
		dt.getFullYear()	// 年
		dt.getMonth()	// 月(0-11)
		dt.getDate()	// 日(0-31)
		dt.getHours()	// 小时(0-23)
		dt.getMinutes()	// 分钟(0-59)
		dt.getSeconds()	// 秒(0-59)

	2、Math
		—— 获取随机数Math.random()  // 用于清除缓存

	3、数组API
		—— forEach 遍历所有元素
			var arr = ['a','b','c']
			arr.foreach(function(item, index){
				console.log(item, index)
			})

		—— every 判断所有元素是否都符合条件
			var arr = [1,2,3]
			var result = arr.every(function(item, index){
				if (item < 4) {
					return true
				}
			})
			console.log(result)

		—— some 判断是否至少有一个元素符合条件
			var arr = [1,2,3]
			var result = arr.some(function(item, index){
				if (item > 4) {
					return true
				}
			})
			console.log(result)

		—— sort 排序【原数组也会改变】
			var arr = [1,4,2,3,5]
			var arr2 = arr.sort(function(a,b){
				// 从小到大
				return a-b

				// 从大到小
				return b-a
			})
			console.log(arr2)

		—— map 对元素重新组装,生成新数组【原数组不会改变】
			var arr = [1,2,3]
			var arr2 = arr.map(function(item, index){
				return '<b>' + item + '</b>'
			})
			console.log(arr2)

		—— filter 过滤符合条件的元素【原数组不会改变】
			var arr = [1,2,3]
			var arr2 = arr.filter(function(item, index){
				if (item >= 2) {
					return true
				}
			})
			console.log(arr2)

	4、对象API
		—— for...in...
			var obj = {
				x: 100,
				y: 200,
				z: 300
			}
			for(var key in obj){
				if (obj.hasOwnProperty(key)) {
					console.log(key, obj[key])
				}
			}

—— 题目
	1、获取2017-06-10格式的日期
		function formatDate(dt) {
			if (!dt) {
				dt = new Date(0)
			}
			var year = dt.getfullYear()
			var month = dt.getMonth() + 1
			var date = dt.getDate()
			if (month < 10) {
				month = '0' + month
			}
			if (date < 10) {
				date = '0' + date
			}
			return year + '-' + month + '-' + date
		}

		var dt = new Date()
		var formatDate = formatDate(dt)
		console.log(formatDate)

	2、获取随机数,要求是长度一致的字符串格式
		var random = Math.random();
		random = random + '0000000000'
		random = random.slice(0, 10)
		console.log(random)

	3、写一个能遍历对象和数组的通用的forEach函数
		—— 自定义函数
			function forEach(obj, fn) {
				var key 
				if (obj instanceof Array) {
					obj.forEach(function(item, index){
						fn(index, item)
					})
				} else {
					for(key in obj) {
						fn(key, obj[key])
					}
				}
			}

		—— 使用
			var arr = [1,2,3]
			forEach(arr, function(index, item){
				console.log(index, item)
			})

			var obj = {
				name: 'xiao',
				age: '20',
				sex: 'nv'
			}
			forEach(obj, function(key, value) {
				console.log(key, value)
			})