变量类型和计算
知识点:
- 变量类型
值类型:数值,逻辑值,字符串等如200,在内存中为与变量储存在一起。赋值给其他变量后,本身不受影响
var a = 100
var b = a
a = 200
console.log(b)//100
引用类型:对象,函数,数组:值储存在单独的内存区域,变量通过指针指向内存区域。赋值给其他值后,其他值变更自身也变更。
var a = {age:20}
var b = a
b.age = 21
console.log(a.age) //21
- 变量计算——强制类型转换
字符串拼接
var a=100 +10 //110
var b=100 +'10' //10010
== 运算符
100 == '100' //true
0 == '' //true
null == undefined //true
if语句
var a = true
if(a){
//执行
}
var b = 100
if(b) {
//执行
}
var c= ''
if (c) {
//不执行 c转换为false
}
逻辑运算
console.log(10 && 0) //0
console.log('' || 'abc') //'abc'
console.log(!window.abc) //true
// 判断一个变量会被当成 true 还是 false
var a = 100
console.log(!!a)
题目:
1、JS中使用typeof能得到哪些类型?
// 值类型
typrof undefined //undefined
typeof 'abc' //string
typeof 123 //number
typrof true //boolean
typeof Symbol('s') // symbol
// 能判断函数
typeof console.log //function
typeof function(){} // function
// 能识别为引用类型(不能再继续识别)
typeof {} //object
typeof [] //object
typeof null //object
2、何时使用===?何时使用==?
//==标准用法(只有这种情况用==)
if(obj.a == null){
// 这里相当于 obj.a ===null || obj,a === undefined ,简写形式
// 这里是jquery 源码中的推荐写法
}
//其他情况全用===
3、JS中有哪些内置函数?
// 内置函数 —— 数据封装对象
Object
Array
Boolean
Number
String
Function
Date
RegExp //正值
Error
//内置对象
Math
JSON
4、JS变量按照储存方式区分为哪些类型,并描述其特点?
值类型:数值,逻辑值,字符串等如200,在内存中为与变量储存在一起。赋值给其他变量后,本身不受影响
var a = 100
var b = a
a = 200
console.log(b)//100
引用类型:对象,函数,数组:值储存在单独的内存区域,变量通过指针指向内存区域。赋值给其他值后,其他值变更自身也变更。
var a = {age:20}
var b = a
b.age = 21
console.log(a.age) //21
5、如何理解JSON?
// JSON 是一个JS 内置对象
// JSON 是一种数据格式
JSON.string ({a:10,b:20}) //对象转换为字符串
JSON.parse('{'a':10,'b':20}') // 字符串转换为对象
6、深拷贝
/**
* 深拷贝
*/
const obj1 = {
age: 20,
name: 'xxx',
address: {
city: 'beijing'
},
arr: ['a', 'b', 'c']
}
const obj2 = deepClone(obj1)
obj2.address.city = 'shanghai'
obj2.arr[0] = 'a1'
console.log(obj1.address.city)
console.log(obj1.arr[0])
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj = {}) {
if (typeof obj !== 'object' || obj == null) {
// obj 是 null ,或者不是对象和数组,直接返回
return obj
}
// 初始化返回结果
let result
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let key in obj) {
// 保证 key 不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用!!!
result[key] = deepClone(obj[key])
}
}
// 返回结果
return result
}
7、 falsely 变量和truely变量
//除此以外都是truly变量
!!0 === false
!!NaN === false
!!'' ===false
!!null ===false
!!undefined === false
!!false === false
if判断时判断的是falsely 变量和truely变量,与或非判断是也是判断falsely变量和truely变量
8、字符串拼接
const a = 100+10 //110
const b = 100+"10" //"10010"
const c = true + 10 // "true10"
原型和原型链
知识点
ES6
1、 类
class 定义类
constructor 构建属性
类中可以定义方法
// 类
class Student {
constructor(name, number) {
this.name = name
this.number = number
// this.gender = 'male'
}
sayHi() {
console.log(
`姓名 ${this.name} ,学号 ${this.number}`
)
// console.log(
// '姓名 ' + this.name + ' ,学号 ' + this.number
// )
}
// study() {
// }
}
// 通过类 new 对象/实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
const madongmei = new Student('马冬梅', 101)
console.log(madongmei.name)
console.log(madongmei.number)
madongmei.sayHi()
2、继承
extend 定义继承的父类
super 执行父类的构造函数
// 父类
class People {
constructor(name) {
this.name = name
}
eat() {
console.log(`${this.name} eat something`)
}
}
// 子类
class Student extends People {
constructor(name, number) {
super(name) // 交给父类
this.number = number
}
sayHi() {
console.log(`姓名 ${this.name} 学号 ${this.number}`)
}
}
// 子类
class Teacher extends People {
constructor(name, major) {
super(name)
this.major = major
}
teach() {
console.log(`${this.name} 教授 ${this.major}`)
}
}
// 实例
const xialuo = new Student('夏洛', 100)
console.log(xialuo.name)
console.log(xialuo.number)
xialuo.sayHi()
xialuo.eat()
// 实例
const wanglaoshi = new Teacher('王老师', '语文')
console.log(wanglaoshi.name)
console.log(wanglaoshi.major)
wanglaoshi.teach()
wanglaoshi.eat()
原型
// class 实际上是函数,可见是语法糖
typeof People //'function'
typeof Student // 'function'
//隐式原型和显示原型
console.log( xialuo.__proto__)
console.log( Student.prototype )
console.log( xialuo.__proto__ === Studnet.prototype )
原型关系
- 每个class 都有显示原型prototype
- 每个实例都有隐式原型__proto__
- 实例的__proto__指向对应class的prototype
基于原型的执行规则
- 获取属性xialuo.name 或执行方法·xialuo.sayhi()时
- 先在自身属性和方法寻找
- 如果找不到则自动去__proto__中查找
原型链
顶层的JS自带prototype中的__proto__ 始终指向null 到此为止!
问题:
1、如何准确判断一个变量是不是数组
instanceof
语法
a instanceof Array
2、手写简易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) {
}
style(data) {
}
}
// const $p = new jQuery('p')
// $p.get(1)
// $p.each((elem) => console.log(elem.nodeName))
// $p.on('click', () => alert('clicked'))
ES5
-
构造函数
function Foo(name,age) { this.name = name this.age = age this.class = 'class-1' //retrun this //函数默认执行这个操作 } var f = new Foo('zhangsan',20) // new 时 this 会先变成空对象 // var f1 = new Foo('lisi',22) // 创建多个对象 -
构造函数-扩展
var a = {} 其实是 var a = new Object() 的语法糖 var a = [] 其实是 var a = new Array() 的语法糖 function Foo(){...} 其实是 var Foo = new Function(...) 使用instanceof 判断一个函数是否是一个变量的构造函数 -
原型规则和示例
1、所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了null 以外)
var obj = {};obj.a = 100;
var arr = []; arr.a =100;
function fn() {}
fn.a =100;
2、所有的引用类型(数组、对象、函数),都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);
3、所有的函数,都有一个prototype(显式原型)属性,属性值也是一个普通的对象
console.log(fn.prototype)
4、所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的‘’prototype"属性值
console.log(obj.__proto__ === Object.prototype)
5、当识图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么回去它的__proto__(即它的构造函数的prototype)中寻找。
// 构造函数
function Foo(name,age) {
this.name = name
}
Foo.prototype.alertName = function () {
alert(this.name)
}
// 创建示例
var f = new Foo('zhangsan')
f.printName = function () {
console.log(this.name)
}
// 测试
f.printName() //可以运行
f.alertName() //找到在prototype 中定义的属性可以运行
//遍历注意事项
var item
for (item in f) {
//高级浏览器已经在 for in 中屏蔽了来自原型的属性
// 但是还是加上这个判断,保证程序的健壮性
if (f.hasOwnProperty(item)) {
console.log(item)
}
}
-
原型链
// 构造函数 function Foo(name,age) { this.name = name } Foo.prototype.alertName = function () { alert(this.name) } // 创建示例 var f = new Foo('zhangsan') f.printName = function () { console.log(this.name) } // 测试 f.printName() //可以运行 f.alertName() //找到在prototype 中定义的属性可以运行 f.toString() //要去 f.__proto__.__proto__中去查找 找不到返回undefined
查找过程如图所示
- instanceof
用于判断引用类型属于哪个构造函数的方法
f instancsof Foo 的判断逻辑是:
f 的__proto__一层一层往上,能否对应到Foo.prototype
题目
1、如何准确判断一个变量是*数组类型
var arr = []
arr instanceof Array //true
typrof arr // 结果object, typeof 是无法判断是否是数组的
2、写一个原型链继承的例子
//理解用实例,面试最好不要用
// 动物
function Animal() {
this,eat = function () {
console.log('animal eat')
}
}
// 狗
function Dog() {
this.bark = function () {
console.log('dog bark')
}
}
Dog.prototype = new Animal()
// 哈士奇
var hashiqi =new Dog()
//实用例子 DOM查询
function Elem(id) {
this.elem = document.getElementId(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')
console.log(div1.html())
div1.html('<p>hello world</p>')
div1.on('click',function(){
alert('clicked')
})
3、描述 new 一个对象的过程
-
创建一个新对象
-
this指向这个对象
-
执行代码,即对this赋值
-
返回this
function Foo(name,age) { this.name = name this.age = age this.class = 'class-1' //retrun this //函数默认执行这个操作 } var f = new Foo('zhangsan',20) // new 时 this 会先变成空对象 // var f1 = new Foo('lisi',22) // 创建多个对象
4、zepto(或者其他框架)源码中如何使用原型链