console.log(2>3); //flase
console.log(3<2<1); //true
console.log(1>2>3); //flase
console.log( [1<2<3,3<2<1] ); //[true, true]
console.log(true==1); //true
console.log(true=="1"); //true,因为true是1,所以“1”会转成1
console.log(true===1); //false boolean和number数据类型不同
console.log(typeof true); //boolean
首先,我们需要知道,在编程语言中 0 == false和1 == true(是0,1不是“0”,“1”)是正确的。
因此在分析3<2<1时,我们可以将其分为两步,首先是3<2返回是flase,也就等价于0。
所以0<1结果自然是true了。
(0,1其实是计算机二进制,输出成true,flase,然后两个number类型比较大小就是比较对应的二进制值,而js的字符串在进行比较时,会根据ASCII码值比较,但ASCII码值也是由二进制转换成十进制得到的)
let a=[1]
let b=[1]
console.log(a==b); //flase
console.log([]==[]); //false 相当于分别创建了两个引用数据类型的变量,指向不同的堆内存地址
因为数组、对象都是引用数据类型,a和b只是两个指针存储在栈中,实则比较的是堆内存地址
console.log(a===b); //flase
let a=[1,2]
let b=a
console.log(b==a); //true //直接赋值,堆内存地址相同
console.log(b===a); //true
那两个数组如何比较值是否相等?
let a=[1,2,3]
let b=[1,2,3]
console.log(a.toString(),b.toString(),a.toString()===b.toString())
console.log(JSON.stringify(a),JSON.stringify(b),JSON.stringify(a)===JSON.stringify(b))
但是依旧会存留问题
1.数组顺序不一致,(可以使用.srot()做一下排序)
2.由于转义成了字符串,会导致原本是数字的数据,会变成字符串类型,可能会影响对比的准确性
console.log(2==[2]); //true
console.log(2==[[2]]); //true 因为左面的2是基本数据类型,所以js解析时候就做了件事 [[2]].toString(),然后就是“2”
console.log(2==[[[2]]]); //true
console.log(2===[[[2]]]); //false
console.log([true]=="true"); //true js解析时候用了toString转换,所以值相同,但类型不同,且js是弱类型语言
console.log([true]==="true"); //false
console.log([true]==true); //false 字符串“true”和true比较,值相当于true字符和1
console.log([true]===true); //false
let arr=[5,2,4]
console.log(arr.toString()); //5,2,4
console.log([]==false); //true [].tostring()结果是空,也就是flase
console.log([]==0);//true
console.log([]=="0"); //false 因为他已经弱类型转换一次成了flase,不能再转换一次成字符0
console.log(false=="0"); //true
console.log(3.toString()); //报错
console.log((3).toString()); //“3” 有括号就不会报错,或者就是下面的定义一个变量
var c=8; console.log(c.toString()); //"8"
console.log(3..toString()); //“3”
console.log(3...toString()); //报错
console.log(.3);// 0.3
console.log(3.); //3
console.log(+5); //5
console.log(-5); //-5
console.log(.3.toString()); //“0.3”
console.log(.3..toString()); //报错
运算符优先级的问题,点运算符会被优先识别为数字常量的一部分,然后才是对象属性访问符
在 JS 中,3.1,3.,.3 都是合法的数字
3.toString() 会被 JS 引擎解析成 (3.)toString() 报错
3..toString() 会被 JS 引擎解析成 (3.).toString() "3"
3...toString() 会被 JS 引擎解析成 (3.)..toString() 报错
.3.toString()会被 JS 引擎解析成(.3).toString() “0.3”
.3..toString()会被 JS 引擎解析成(.3)..toString() 报错
1. (function(){
var x=y=1
})()
console.log(y); //1
console.log(x); //x is not defined
2. (function(){
var x=1,y=1 //逗号代表这条语句还未结束
})()
console.log(y); //y is not defined
console.log(x); //x is not defined
这道题目涉及到变量提升的范围,以及赋值语法。
var x=y=1 等价于 var x=y; y=1; 这里的y会被提升至全局域,所以是上述答案。
var x=1,y=1 等价于var x=1; var y=1, 这样写的话,x,y都是局部变量,不会被提升。
函数的函数声明有一个重要特征 —— 函数声明提升
1.
keqing(); //Hi~
function keqing(){
alert('Hi~');
}
函数:在读取执行代码之前会先读取函数声明
2.
keqing(); // Uncaught TypeError: keqing is not a function
console.log(keqing); //undefined
var keqing = function(){ //
alert('Hi~');
}
console.log(keqing); //f(){}
函数表达式:没有函数声明提升,在执行前必须先赋值,相当于只是变量提升,还要赋值后才可以用,但值不会提升
3.
console.log(a); //undefined 变量只是声明提升,但还没赋值,值不会提升
var a=5
console.log(a); //5
1. for(var i=0;i<2;i++) //这个地方i++与++i都没关系,因为没直接参与运算
{
setTimeout(() => {
console.log(i++); //2 3 相当于先打印再加,打印即参与运算
console.log(i); //3 4
}, 1000);
}
2. for(var i=0;i<2;i++)
{
setTimeout(() => {
console.log(++i); //3 4 当于先加再打印
console.log(i); //3 4
}, 1000);
}
3.
for(let i=0;i<2;i++)
{
setTimeout(() => {
console.log(++i); //1 2
console.log(i); //1 2
}, 1000);
}
var a=[1,2,3]
var b=[1,2,3]
var c=[1,2,4]
var d=a
console.log(a.toString()); //1,2,3
console.log(d==a); //true 堆中相同内存地址
console.log(d===a); //true 堆中相同内存地址
console.log(a==b); //flase 堆中不同内存地址
console.log(a===b); //false 堆中不同内存地址
console.log(a>c); //false 相当于两边[1,2,3].toString()转化为字符串,再先比较第一个值的ASCALL码值,相同再比较第二个,以此类推
console.log(a<c); //true
var a = {}, b = Object.prototype;
[a.prototype === b, Object.getPrototypeOf(a) === b]
结果为[false,true]
首先prototype属性是函数才有的属性,对象是没有的,对象要想访问原型对象需要用object.__proto__,
因此a.prototype返回undefined,因为a是一个对象,它没有prototype属性。
Object.getPrototypeOf(a)相当于a.__proto__,所有用Object()创建的对象它们的原型对象都指向同
一个对象(包括字面量形式创建的对象),因此Object.getPrototypeOf(a) === b返回true.
setTimeout(function () {
console.log('three');
}, 0);
Promise.resolve().then(function () {
console.log('two');
});
console.log('one');
// one
// two
// three
需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行执行,不是马上执行,也不是在下一轮“事件循环”的开始时执行
原因:传递到 then() 中的函数被置入了一个微任务队列,而不是立即执行,这意味着它是在 JavaScript 事件队列的所有运行时结束了,事件队列被清空之后,才开始执行
所以定时器是最后被调起,最后执行
Promise.resolve().then(() => console.log(2)).
then(() => console.log(3)).
catch(() => console.log(4));
console.log(1);
// 1, 2, 3 先执行1再执行resolve的Promise对象的回调函数
Promise.resolve(8).then((res) => console.log(res)).
then((res) => console.log(res)).
catch(() => console.log(4));
console.log(1);
// 1, 8, undefined 先执行1再执行resolve的Promise对象的回调函数,第一个then接收完回调函数参数res后,第二个then接收不到了
Promise.reject().then(() => console.log(2)).
then(() => console.log(3)).
catch(() => console.log(4));
console.log(1); // 1, 4 先执行1再执行reject的Promise对象的回调函数
resolve()本质作用:(reject同理)
resolve()是用来表示promise的状态为fullfilled,相当于只是定义了一个有状态的Promise对象,但是并没有调用它;
promise调用then的前提是promise的状态为fullfilled;
只有promise调用then的时候,then里面的函数才会被推入微任务中
console.log([,,,,,]); //[empty × 5],就是5个undefined
console.log([,,,,,].length); //5
console.log([,,,,,].join(",")); //,,,, 五个元素,则连接只需要四个字符并且每个元素都是空的
let c={d:5}
let d={d:5}
let e=c
console.log(e===c); //true 对象(引用数据类型)指向相同的内存地址
console.log(c===d); //false 对象(引用数据类型)指向不同的内存地址
var a = 111111111111111110000,
b = 1111;
a + b;
是一道考查JavaScript数值的题,由于JavaScript实际上只有一种数字形式IEEE 754标准的64位双精度浮点数,其所能
表示的整数范围为-2^53~2^53(包括边界值)。这里的111111111111111110000已经超过了2^53次方,所以会发生精度丢失的情况。
这个又一次考察JavaScript中的最大值问题,JavaScript中最大值是Math.pow(2, 53)=9007199254740992,计算
过程中如果超出这个最大值范围就不准确了,但是怎么个不准确法,是不确定的。这里输出111111111111111110000, 还是a的值。
var two = 0.2;
var one = 0.1;
var eight = 0.8;
var six = 0.6;
console.log([two-one === one, eight - six === two]) //[true, false]
console.log( eight-six); //0.20000000000000007
console.log(two-one); //0.1
console.log(0.1+0.2); //0.30000000000000004
console.log(0.8+0.6); //1.4
console.log(0.2-0.1); //0.1
这个考察的是JavaScript数字精度问题,JavaScript的Number类型为双精度IEEE 754 64位浮点类型,这个问题造成0.1 + 0.2!= 0.3,0.8 - 0.6 != 0.2等等。
遇到IEEE 754标准中的浮点数并不能精确地表达小数时,可以使用toFixed方法转换下,toFixed方法可以规定保留几位小数点
( eight - six ).toFixed(1) == two //true toFixed方法可以规定保留几位小数点
( eight - six ).toFixed(1) === two //false 转换后的类型不同
console.log( typeof (eight-six)); //number
console.log(typeof (eight-six).toFixed(1) ); //string
function foo(){}
var old=foo.name
console.log(old); //foo
foo.name="bar" //不会改变函数的名字
console.log(foo.name); //foo
在Javascript规范中提到,要比较相等性之前,不能将 null 和 undefined 转换成其他任何值,并且规定null 和 undefined 是相等的。
console.log(undefined == null); //true
console.log(undefined==false); //false
console.log(null==false); //false
有文章对此进行了解释,大致是下面的意思:undefined的布尔值是false,null的布尔值也是false,所以它们在比较时都转化为了false,所以 undefined == null 。但这种解释是错误的。
在Javascript规范中提到,要比较相等性之前,不能将 null 和 undefined 转换成其他任何值,并且规定null 和 undefined 是相等的。
console.log('' == 0 == false); //false js是弱类型语言,可以随意转换
function dy() {
this.get=function(){
console.log(1);
}
}
dy.gets=function(){console.log(2);} //只相当于dy这个函数对象的一个方法
dy.a=88 //只相当于dy这个函数对象的一个变量
dy.gets() //2 只有通过这种方法才可以调用
console.log(dy.a); //88
dy.prototype.get=function(){console.log(3);}
let newdy=new dy()
newdy.get() //1 实例中要是没有get方法才会去该实例的原型中找
console.log(newdy.a); //undefined
newdy.gets() //newdy.gets is not a function
var a=1
var b=8;
var A={v:2}; //加个;隔开 不加分号跟下面的自执行函数混在一起会报错
(function(a,A){
console.log(a); //1
console.log(A); //{v: 2}
A.v=5
a=A.v
b=9 //全局的b
console.log(a); //5 形参a的值
})(a,A)
console.log(A.v); //5 引用数据类型占用一块相同的内存空间,所以可以通过形参改变值
console.log(a); //1 而基本数据类型,会任意开辟内存空间,所以形参重新开辟了内存空间,不会影响到全局的值
console.log(b); //9
//自执行函数不传参
for (var i= 0; i < 3; i++) {
(function(i){
console.log(i); //3个undefined 形参永远要接收实参传进来的值
setTimeout(() => {
console.log(i); //3个undefined 形参永远要接收实参传进来的值
}, 1000);
})()
}
//自执行函数传参,且用var声明i
for (var i= 0; i < 3; i++) {
(function(i){
console.log(i); //0 1 2 实参传进来的值
setTimeout(() => {
console.log(i); //0 1 2 因为这个定时器存取了每次形参i的值,不是全局的i
//在函数内部执行时,形参就默认是局部变量,所以会先在局部找,找不到再向全局中找(由内到外)
}, 1000);
})(i)
}
//自执行函数传参,且用let声明i ,结果一样
for (let i= 0; i < 3; i++) {
(function(i){
console.log(i); //0 1 2 实参传进来的值
setTimeout(() => {
console.log(i); //0 1 2 因为这个定时器存取了每次形参i的值,不是全局的i
}, 1000);
})(i)
}
console.log(-9%2); //-1
console.dir(-10%2); //-0
console.log(-10%2===0); //true
console.log(Infinity%2); //NaN
var val = 'smtg';
console.log('Value is ' + (val === 'smtg') ? 'Something' : 'Nothing'); //Something
第一感觉输出Value is Something,但运行后发现输出Something,就是一个优先级的问题,上述代码等价于
console.log(('Value is ' + (val === 'smtg')) ? 'Something' : 'Nothing'),
//('Value is ' + (val === 'smtg'))结果为Value is true,所以最后输出Something
console.log('Value is ' + val === 'smtg')// flase
console.log('Value is ' + (val === 'smtg'))//Value is true
解析时js代码从前向后解析
var name="Wordld";
function name2(){
console.log(name); //undefined 因为后面又声明了var name="jack",这会导致name变量提升到前面,会先从局部作用域中找name变量,但赋值没提升,所以就undefined
if(typeof name==="undefined") //true
{
var name="jack"
console.log("hellp"+name); //hellpjack
}
else
{
console.log("hellp"+name);
}
}
name2()
function isOdd(num) {
return num%2==1
}
function isEven(num) {
return num%2==0
}
function isSane(num)
{
return isOdd(num)||isEven(num)
}
let arr=[8,16,-9,Infinity]
let newarr= arr.map(isSane)
console.log(newarr); //[true, true, false, false]
//这就是js是弱类型语言的弊端,可以随意转换,而不需要强制转换
var a=[0]
if ([0]) { //数组在这里表示有值所以就是true
console.log(a==true); //[0].toString() 是0,所以是false
console.log([0]==false); // true
}else
{
console.log("Xxx");
}
//
if ([]) { //数组在这里表示有值所以就是true
console.log(5); //5
}
//
var a
if (a) { //a无值,则为false
console.log(555); //不执行
}
//
if ("0") {
console.log(555); //555
}else
{
console.log("Xxx");
}
//
if (0) {
console.log(555);
}else
{
console.log("Xxx");//Xxx
}
var arr=new Array(3)
arr[0]=2
let newarr=arr.map(function(item){return "1"})
console.log(arr); // [2, empty × 2] map函数不改变原数组
console.log(newarr); //['1', empty × 2] 只遍历映射有值的索引对应的元素
function sid(arr) {
arr[0]=arr[2] //
}
function bar(a,b,c) {
console.log(arguments); //[1,1,1] arguments参数数组是引用数据类型,占用同一内存地址
c=10; //对参数的重新赋值,生效
console.log(arguments); //[1,1,10]
sid(arguments)
console.log(arguments); //[10,1,10]
return a+b+c
}
console.log(bar(1,1,1)) //21
var a=/123/
b=/123/;
console.log(a==b); //false 正则(RegExp)和日期(Date)是两个特殊的对象类型即引用数据类型
console.log(a===b); //false 两个变量指向不同的堆内存地址
function name() {
temp=0
}
name()
console.log(temp); //0
//
function name() {
temp=0
}
console.log(temp); //temp is not defined name只是函数声明提升,但要被调用才会执行函数里面的内容
var name="张三"
function fun(a)
{
a="李四"
}
fun(name)
console.log(name); //张三 因为name是基本数据类型,在函数中执行重新开辟了内存空间储存参数a的值,不会影响name的值
//
var obj={
name:"张三"
}
function fun(a)
{
a.name="李四"
}
fun(obj)
console.log(obj.name); //李四 因为obj是引用数据类型,在函数中执行时操作的是同一堆内存空间,不会随意开辟新的内存空间
<div id="app">
<button @click="add">添加</button>
<span ref="test">{{msg}}</span>
</div>
<script>
const app = Vue.createApp({
data() {
return {
msg:"ss"
}
},
methods: {
add(){
this.msg="dd"
//nextTick() 可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 async await 返回的 Promise再继续执行。
this.$nextTick(function(){
console.log( this.$refs.test.innerHTML); //dd xuranr
//不用nextTick而直接打印,结果会是ss,因为那时候数据虽然更新,但DOM还没更新完成
})
}
},
})
app.mount("#app")
function Person(first,last)
{
this.first=first;
this.last=last;
return 55
}
const ly=new Person("ss","cxc")
const sa=Person("sa","ss")
console.log(ly); //Person {first: 'ss', last: 'cxc'}
console.log(sa); //55 没return返回值得话就是undefined
var a=[2,,3]
console.log(JSON.stringify(a)); //[2,null,3] JSON.stringify()将JS对象转换为JSON格式的字符串
console.log(typeof JSON.stringify(a)); //string
console.log(a.toString()); //2,,3
console.log(`${(x=>x)('I LOVE')} to program`); //I LOVE to program
console.log(`${(x=>x)('I')}`); //I 相当于自执行函数传入参数I,然后返回I
//ES6解构赋值
let [a,b,c,d,e]="her"
console.log(e); //undefined
console.log(c);//r