数据类型
原始类型有哪几种?null 是对象嘛?
- null
- undefined
- string
- boolean
- number
- symbol (es6 新增)
typeof null 输出的Object,但是对于js来说它还是作为一个基本类型
typeof :
原始数据类型的判断采用 typeof ,
原理: 不同的对象在底层都表示为二进制, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0, 自然前三位也是 0, 所以执行 typeof 时会返回“object”。
instanceof:
引用数据类型的判断采用 instanceof
原理:通过原型链去判断
原始类型和对象类型的区别
原始类型存储的是值,对象类型存储的是一个地址
- 判断一个变量是否未定义
首先如果单纯的使用未定义,浏览器会报错
typeof xx == undefined
用这个可以判断是否未定义
对象
for/in、Object.keys 和 Object.getOwnPropertyNames 对属性遍历有什么区别?你还知道其他遍历对象属性的方式吗?请说明。
ES6 一共有 5 种方法可以遍历对象的属性。
var parent = {}
Object.defineProperties(parent, {
a: {
value: 1,
writable: true,
enumerable: true,
configurable: true
},
b: {
value: 1,
writable: true,
enumerable: false,
configurable: true
},
[Symbol('parent')]: {
value: 1,
writable: true,
enumerable: true,
configurable: true
}
})
var child = Object.create(parent, {
c: {
value: 1,
writable: true,
enumerable: true,
configurable: true
},
d: {
value: 1,
writable: false,
enumerable: true,
configurable: true
},
e: {
value: 1,
writable: true,
enumerable: false,
configurable: true
},
f: {
value: 1,
writable: true,
enumerable: true,
configurable: false
},
[Symbol('child')]: {
value: 1,
writable: true,
enumerable: true,
configurable: true
}
})
- for...in
for...in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
for (const key in child) {
console.log(key)
}
// c d f a
- Object.keys(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
Object.keys(child)
// ["c", "d", "f"]
- Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
Object.getOwnPropertyNames(child)
// ["c", "d", "e", "f"]
- Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols(child)
// [Symbol(child)]
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
- Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
Reflect.ownKeys(child)
// ["c", "d", "e", "f", Symbol(child)]
类数组转换为数组有哪几种实现方式?
类数组对象:只包含使用从零开始,且自然递增的整数做键名,并且定义了length表示元素个数的对象,我们就认为他是类数组对象!
var obj = {
0: 'a',
1: 'b',
length: 2
}
console.log(Array.from(obj))
console.log(Array.prototype.slice.call(obj))
console.log([].slice.call(obj))
字符串
常见的字符串方法
- str.charAt(index); 返回子字符串,index为字符串下标
- str.charCodeAt(index); 返回字符串的unicode编码
- str.indexOf(searchString,startIndex); 返回子字符串第一次出现的位置,从startIndex开始查找
- str.lastIndexOf(searchString,startIndex); 从由往左找子字符串,找不到时返回-1
- str.substring(start,end); 两个参数都为正数,返回值:[start,end) 也就是说返回从start到end-1的字符(有一点比较重要的是,start和end的参数是可以互换的,小的在前面,大的在后面)
- str.slice(start,end); 两个参数可正可负,负值代表从右截取,(-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。) 返回值:(start,end) 也就是说返回从start到end-1的字符
- str.substr(start,length); start参数可正可负,负数代表从右截取
区别 - str.split(separator,limit); 参数1指定字符串或正则,参照2指定数组的最大长度
- str.replace(rgExp/substr,replaceText) 返回替换后的字符串
- str.match(rgExp); 正则匹配, 匹配到则返回匹配的文字
字符串比较
字符串之间的比较:比较第一个字符的unicode编码值,第一个字符要是相同,就比较第二个
数组
数组常用方法.png常用的数组方法
- map() 方法按照原始数组元素顺序依次处理元素。
注意:map() 不会对空数组进行检测。
注意: map() 不会改变原始数组。
删除数组的方法 - splice
- arr[1] delete[i] delete方法删除掉数组中的元素后,会把该下标出的值置为undefined,数组的长度不会变
会改变原来数组的有:
pop()---删除数组的最后一个元素并返回删除的元素。
push()---向数组的末尾添加一个或更多元素,并返回新的长度。
shift()---删除并返回数组的第一个元素。
unshift()---向数组的开头添加一个或更多元素,并返回新的长度。
reverse()---反转数组的元素顺序。
sort()---对数组的元素进行排序。
splice()---用于插入、删除或替换数组的元素。
map 与 forEach的区别
- forEch 会改变原来的数组,而map不会
let arr = [1, 2, 3, 4, 5];
arr.forEach((num, index) => {
return arr[index] = num * 2;
});
// arr = [2, 4,6,8,10]
arr.map((num,index)=> {
return num * 2;
})
// arr = [1, 2, 3, 4, 5];
this
如何正确的理解this
- 案例1 先来看一段函数调用
function foo() {
console.log(this.a)
}
var a = 1
foo()
const obj = {
a: 2,
foo: foo
}
obj.foo()
const c = new foo()
分析:
- 在没有任何调用的情况, foo()的this是指向window
- obj.foo(), 谁调用this的指向就会指向谁
- new出来的对象,就绑定在c上
- 案例2 bind
let a = {}
let fn = function () { console.log(this) }
fn.bind().bind(a)()
分析:
你们以为输出的结果是a?其实不然,bind函数所绑定都是由第一次绑定的值来决定,也就是fn.bind() => window
- this有限级说明
首先,new 的方式优先级最高,接下来是 bind 这些函数,然后是 obj.foo() 这种调用方式,最后是 foo 这种调用方式,同时,箭头函数的 this 一旦被绑定,就不会再被任何方式所改变。
闭包
关于闭包的理解
闭包是指,函数中调用函数,函数A中有函数B的存在,函数B中调用函数A的变量。
function A() {
let a = 1
window.B = function () {
console.log(a)
}
}
A()
B() // 1
用途. 使用闭包去处理var关键字的问题
for (var i = 1; i <= 5; i++) {
;(function(j) {
setTimeout(function timer() {
console.log(j)
}, j * 1000)
})(i)
}
缺点:
- 由于闭包中的变量都是存储在内存中,所有很容易导致内存泄漏
- 闭包中会改变父级作用域的变量值,如果把父函数当作一个对象,闭包函数当作公有方法,那么里面的成员变量就要慎用,因为闭包函数会改变其父类的变量,从而影响其他的调用
深拷贝和浅拷贝
对于深拷贝和浅拷贝的理解
- 浅拷贝
可以使用扩展运算符(...)
let a = {
age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1
- 可以使用Object.assign(a, {1,23})
- 深拷贝
- 递归考虑
- for 循环
原型链
原型链的一些要点
- 如何访问
- 标准原型访问器Object.getPrototypeOf(object)
- 非标准访问器object.proto
- 通用访问器,object.constructor.prototype
- 原型上的constructor指向函数本身
- Object.prototype确实一个特例——它的proto指向的是null
- 原型定义的一些公用的属性和方法;利用原型创建出来的新对象实例会共享原型(的所有属性和方法)。
下面这张图展现了原型链的整个模型
原型链推荐文章 原型链精选
网友评论