作为一个普通的JS初学者,从神三元大佬的知识梳理文章中受益匪浅,写下我的学习笔记吧。
JS数据类型
function test(person) {
person.age = 26
person = {
name: 'hzj',
age: 18
}
return person
}
const p1 = {
name: 'fyq',
age: 19
}
const p2 = test(p1)
console.log(p1) // { name: 'fyq', age: 26 }
console.log(p2) // { name: 'hzj', age: 18 }
test
函数中的实参person
是p1
对象在堆中内存地址的copy
,调用person.age = 26
改变了p1
的值,但随后person
又被重写覆盖了,变成了另一块内存空间的地址,并且在最后将这另外一份内存空间的地址返回,赋给了p2
。
研究一下 前五个貌似是对象,因为他们拥有方法,但他们是不可变的?
数字、字符串、布尔值并不是对象,但是它们却拥有属性和方法。这是因为在引用它们的属性和方法时会分别通过调用new Number()
、new String()
、new Boolean()
包装对象来转换成对象,该对象继承了对应的方法来处理属性的引用,一旦引用结束,便会销毁这个临时对象。null
和undefined
没有包装对象,访问它们的属性会报类型错误。
console.log(typeof 1); //number
console.log(typeof new Number(1)); //object
1 === new Number(1) //fasle
这里把1包装成一个对象,这就是原始类型和包装对象的区别。
let x = 32;
console.log(x.toString(2)); //100000
// 创建object实例 调用实例方法 销毁实例
方法和属性也可用于原始值,因为JS在执行方法和属性时将原始值视作对象。简单数据类型不能添加属性,但是除了null
和undefined
,其他的都可以访问属性,所以他们拥有对象的特征,但其实还是简单数据类型而非对象。
JS精度损失
console.log(0.1 + 0.2); // 0.30000000000000004
JS不分整型和浮点型,两个浮点数相加,转换成二进制后会无限循环,由于标准位数的限制后面多余的位数会被截掉导致精度损失。
BigInt
在JS中,所有的数字都以双精度64位浮点格式表示,这导致JS中的Number无法精确表示非常大的整数,它会将非常大的整数四舍五入,JS中的Number类型只能安全地表示-9007199254740991(-(2^53-1))
和9007199254740991((2^53-1))
,任何超出此范围的整数值都可能失去精度。
const theBiggestInt = 9007199254740991n
console.log(theBiggestInt, typeof theBiggestInt); // 9007199254740991n 'bigint'
console.log(theBiggestInt + 1n); // 9007199254740992n
console.log(theBiggestInt * 10n); // 90071992547409910n
JS类型装换
===
叫做严格相等,是指:左右两边不仅值要相等,类型也要相等 叫做严格相等。==
不像===
那样严格,对于一般情况,只要值相等,就返回true
,但==
还涉及一些类型转换。
对象转原始类型
// 优先调用toPrimitive,最后调用toString
var obj = {
value: 3,
valueOf() {
return 4;
},
toString() {
return '5'
},
[Symbol.toPrimitive]() {
return 6
}
}
console.log(obj + 1); // 输出7
闭包
- 函数内部嵌套函数 包含被引用变量(函数)的对象。
闭包产生的本质就是,当前环境中存在指向父级作用域的引用。
var f3;
function f1() {
var a = 2
f3 = function() {
console.log(a);
}
}
f1();
f3(); // 2
调用f1()
给f3()
赋值,此时f3()
拥有window
、f1
和f3
本身这几个作用域的访问权限,变量f3
存在着父级作用域的引用,因此产生了闭包。
JS实现继承
function Parent () {
this.name = 'parent';
this.play = [1, 2, 3];
}
function Child() {
Parent.call(this);
this.type = 'child';
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
面向组合继承
面向组合就是先设计一系列零件,然后将这些零件进行拼装,来形成不同的实例或者类。代码干净,复用性也很好。这就是面向组合的设计方式。
function drive(){
console.log("wuwuwu!");
}
function music(){
console.log("lalala!")
}
function addOil(){
console.log("哦哟!")
}
let car = compose(drive, music, addOil);
let newEnergyCar = compose(drive, music);