JavaScript复习-0
JavaScript数据类型
原始Primitive类型:
Number
、String
、Boolean
、Undefined
、Null
、Symbol
、Bigint
引用类型
Object
、Array
、Date
、Function
Symbol和Bigint
Symbol
表示唯一、不可变的值。用于确保对象属性使用唯一标识符,不会发生属性名冲突的危险; Symbol.for
返回一致的结果
BigInt
是一种数字类型的数据,它可以表示任意精度格式的整数,使用BigInt
可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围
常见 Symbol
// Object.prototype.toString
Symbol.toStringTag
// 将对象转换为相应的原始值(隐式类型转换)
Symbol.toPrimitive
// 迭代器
Symbol.Iterator
var vs let/const
- 作用域问题
- 重复声明/赋值问题
- 变量提升
- 暂时性死区
数据属性/访问器属性
对象的属性有两种类型,数据属性和访问器属性
- 创建对象时默认就存在的属性为数据属性
- 通过
Object.defineProperty
设置的属性描述符中含有set/get
的属性为访问器属性
内部属性[[Class]]
所有对象(typeof
返回为object
)都包含有一个内部属性[[Class]]
,该属性不能直接访问,
可使用Object.prototype.toString
来查看
ES6移除了这个属性
Object.prototype.toString.call([])
//"[object Array]"
Object.prototype.toString.call(() => {})
// "[object Function]"
Object.prototype.toString
拿到变量准确的类型
Object.prototype.toString.call([])
//"[object Array]"
Object.prototype.toString.call(() => {})
// "[object Function]"
/*
基本类型值string、number、boolean都可以打印这是因为JavaScript为基本类型值包装
了一个封装对象使它们变成了对象,而String()、Number()、Boolean()上有属性[[Class]]
*/
Object.prototype.toString.call(2)
// "[object Number]"
Object.prototype.toString.call("a")
// "[object String]"
可通过重写变量的toString方法修改输出
const a = {
get [Symbol.toStringTag]() {
return 'A';
}
}
Object.prototype.toString.call("a")
// "[object A]"
上下文、作用域链、闭包
~~ (执行)上下文:变量或函数的上下文决定 了它们可以访问哪些数据,以及它们的行为。每个上下文都有一个关联的变量对象(variable object) ,存储这个上下文中定义的所有变量和函数。函数局部上下文中的叫做活动对象(activity object)(活动对象最初只有一个定义变量arguments
,全局上下文中没有这个变量)。上下文会在其所有代码都执行完毕后被销毁(全局上下文会在应用程序退出前才会被销毁,比如关闭网页或退出浏览器)~~
作用域链:执行上下文的集合。上下文中的代码在执行时会创建变量对象(VO) 的一个作用域链,代码正在执行的上下文的变量对象始终位于作用域链的最前端。全局上下文的变量对象始终位于作用域链尾部
闭包(JS高程4):指那些引用了另一个函数作用域中变量的函数。在一个函数内定义的函数会把其包含函数的活动(变量)对象添加到自己的作用域链中,外部函数的活动(变量)对象是内部函数作用域链上的第二个对象。闭包的本质是内部函数加长了其作用域链
闭包(MDN):一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)
function createComparisonFunction(propertyName) {
return function(object1, object2) {
let value1 = object1[propertyName];
let values = object2[propertyName];
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
}
let compare = createComparisonFunction("name");
let result = compare({ name: "Nicholas" }, { name: ""Matt });
作用域和上下文的区别:
作用域是静态的,只要函数定义好了就一直存在并且不再发生变化。执行上下文是动态的,调用函数时创建,调用结束后会释放。上下文中包括了作用域
this
- 先判断函数类型(箭头函数?bind生成?普通函数?)
- 普通函数判断调用方式(new?foo()?obj.foo()?)
- 不管
bind
几次,fn
中的this
始终由第一次bind
决定 - 箭头函数中的
this
一旦被绑定就不会再改变
function fn() {
console.log(this?.a);
}
let a = 12;
const obj = {
a: 13,
fn
};
const obj2 = {
a: 14,
fn: obj.fn,
fn2() {
fn();
},
};
fn(); // undefined
obj.fn(); // 13
obj2.fn(); // 14
obj2.fn2(); // undefined
==时的类型转换
对象转原始类型
对象转原始类型会调用内置的[[ToPrimitive]]函数:
- 如果存在
Symbol.toPrimitive()
方法,调用后返回 - 调用
valueOf()
,如果转换为原始类型则返回(使用obj.valueOf = xxx
来定义) - 调用
toString()
,如果转换为原始类型则返回 - 如果都没有返回原始类型则报错
原型
每个构造函数都有(prototype
)一个原型对象,原型有一个属性(constructor
)指回构造函数,而实例有一个内部指针(__proto__
)指向原型
如果原型是另一个类型的实例呢?那就意味着这个原型本身有一个内部指针指向另一个原型,相应地如果另一个原型也有一个指针指向另一个构造函数。这样就在原型和实例之间构造了一条原型链。
__proto_
_指向构造函数的原型,存在于对象中,指向原型
prototype
存在于函数中,指向原型
function User() {}
const tom = new User();
tom.__proto__ === User.prototype // true
User.prototype.constructor === User // true
new
过程:
- 在内存中创建一个新的空对象
- 这个新对象内部的
__proto__
指针被赋值为构造函数的prototype
值 - 构造函数内部的
this
被赋值为这个新对象(即this
指向新对象) - 执行构造函数内部的代码(给新对象添加属性)
- 如果构造函数返回非空对象,则返回该对象;否则返回刚创建的新对象
function create() {
let obj = new Object()
let Con = [].shift.call(arguments)
obj.__proto__ = Con.prototype
let result = Con.apply(obj, arguments)
return typeof result === 'object' ? result : obj
}