【前端】原生js笔记

js ‘0’

if ('0') console.log('true');
if ('0' == false) console.log('true');
//两句都会执行

在js做比较的时候,有这样的三条规则:
如果比较的两者中有boolean,会把 boolean 先转换为对应的 number,即 0 和 1(false是0,1是true)
如果比较的双方中有一方为number一方为string,会把string转换为数字
把string直接转换为boolean的时候,空字符串‘’转换为 false,除此外的一切字符串转换为 true

原文链接:https://blog.csdn.net/l905128009/article/details/72353532

const let var

ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

JS 变量声明 const let var
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
for(var i=0;i<5;i++){
    setTimeout(()=>console.log(i),0);
}
//5 5 5 5 5 

for(let i=0;i<5;i++){
    setTimeout(()=>console.log(i),0);
}
//0 1 2 3 4 

相等判断

[1,2]==[1,2]是false,如果要判断相等可以toString()以后判断字符串是否相等

变量提升

console.log(a);
var a=26;
//等价于以下代码,输出undefined
var a;
console.log(a);
a=26;

let 不会提升

逻辑与和逻辑或

//与
var arr=[1,2,3,5];
var arr2=[1,2]
console.log(arr&&2);//输出2,第一个为对象,返回第二个操作数
console.log(arr&&arr2);//输出[ 1, 2 ],即两个对象返回第二个对象
console.log(true&&arr);//输出[ 1, 2, 3, 5 ]
console.log(1&&arr);//输出[ 1, 2, 3, 5 ],第一个表达式求值为true,第二个操作数是对象,则会返回对象
//存在短路

//或
console.log(0||arr);//[ 1, 2, 3, 5 ],第一个false,返回第二个对象
console.log(arr||arr2);//[ 1, 2, 3, 5 ],两对象返回第一个
console.log(arr||true);//[ 1, 2, 3, 5 ],第一个是对象就返回第一个
console.log(arr||false);//[ 1, 2, 3, 5 ]
//存在短路

关系操作符

"Black"<"apple" //true, 字符串比较按照字符编码比较,小写字母的编码比大写的打
"23"<"3"   		//true
"23"<3 			//false
"a"<3			//false,a转化成了NaN
NaN<3			//false, NaN比较永远是false
NaN>=3			//false

相等操作符

//==, != 会进行强制类型转换
bool->number;1==true, 0==false, 2!=true
string == number->number == number; 
null==undefined, nullundefined不能转化为其他类型
NaN!=任何操作数,包括NaN!=NaN
//obj1与obj2比较看是不是指向同一个对象


//===, !==不进行转换,全等操作符
55!=="55"
null!==undefined

Number相关

关于js/ts对-2147483648的处理。 js的number类型是64位的,但是当js执行位操作后,将会转化位32位的有符号数。

var x=-2147483648;
console.log(-x);//2147483648
console.log((-x)>>1);//-1073741824
console.log(-2147483648>>1==2147483648>>1);//true
console.log(-x>>>1);//1073741824,无符号右移,符合逻辑

无穷:

console.log(Infinity + Infinity); // Infinity
console.log(Infinity - Infinity); // NaN
console.log(Infinity * Infinity); // Infinity
console.log(Infinity / Infinity); // NaN
console.log(Infinity * 0);        // NaN
console.log(Infinity-1===Infinity) //true

隐式转换
一般来说,对象到字符串的转换经过了如下步骤:
1.如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,js将这个值转换成字符串,并返还这个字符串结果。
2.如果对象没有toString()方法,或者这个方法并不返回一个原始值,那么js将调用valueOf()方法。
3.否则,js无法从toString()或者valueOf()获得一个原始值,因此这时它将抛出一个类型错误异常。

一般来说,对象到数字的转换过程中,js做了同样类似的事情,但这里它会首先尝试使用valueOf()方法:
1.如果对象具有valueOf()方法,后者返回一个原始值,则js将这个原始值转换成数字,并返回这个数字。
2.否则,如果对象具有toString()方法,后者返回一个原始值,则js将转换并返回。
(首先js转换成相应的字符串原始值,再继续将这个原始值转换成相应的数字类型,再返回数字)
3.否则,js抛出一个类型错误异常。

var a = { 
    i: 1, 
    toString: function () { 
        return a.i-- 
    }
}
console.log(a == a-1)

//上述输出等效为
console.log(Number(a)-1==Number(a))//显式转换-1必须写左边,此时左右两边都是0,如果函数中是--a.i则两者都是-1

装箱:将基本数据类型转换为对应的引用类型的操作(装箱又分为隐式装箱和显式装箱);
拆箱:把引用类型转换成基本数据类型。
  基本类型不能有属性和方法,当给它们添加属性的时候系统会自动进行包装类并销毁:

var num = 1;
num.len = 2;
//上一行代码会产生如下过程:
// new Number(1).len =2; 
// delete len;
// 也就是会先添加len属性,当前语句执行结束后即销毁,所以下一行打印num还是1,没有len属性。
console.log(num, num.len);//1 undefined
var num = new Number(1);
num.len = 2;
console.log(num); // Number {1, len: 2}

script标签问题(应放在/body之前)

不论是多个外部脚本还是内部脚本,作用域是相同的,都不能let多次声明同一个变量

按照HTML5标准中的HTML语法规则,如果在/body后再出现script或任何元素的开始标签, 都是parse error,浏览器会忽略之前的/body,即视作仍旧在/body内。 所以实际效果和写在/body之前是没有区别的。 总之,这种写法虽然也能work,但是并没有带来任何额外好处, 实际上出现这样的写法很可能是误解了“将script放在页面最末端”的教条。所以还是不要这样写为好。

扩展运算符用于拷贝对象

可在构建字面量对象时,将对象表达式按照键值对的方式展开 其中 构造字面量对象时,进行克隆或者属性拷贝(这是ECMAScript
2018规范新增特性): 即形如 let objClone = { …obj }; 注意:这个地方,不要与上面1和2中的情况混淆 ,
1和2中的…后面必须要是可迭代对象 而这里只是 ECMAScript 2018规范对 字面量对象增加了展开特性 这个新增特性
https://blog.51cto.com/u_15087089/2599274

对象相关

1. 对象定义

  1. obj=new Object(); obj.attr1=xxx …
  2. 对象字面量: obj={…} 这里的大括号标识一个表达式上下文(与语句上下文区分),该方式 不调用Object构造函数,数组如果写成字面量[1,2,3…]也不会调用Array构造函数

2. ES6对象扩展用法

var abc = "xyz";
var obj1={a:1};
var obj2={b:2};
var foo = {
    abc,//简洁表达法
    ["hh"+"HH"]:"hhh",  //属性名表达式(不可以简介表达)
    [abc]: 100 ,
    [obj1]:"obj1",//表达式是对象的话将转为字符串'[object Object]',同时obj1被覆盖
    [obj2]:"obj2"
};
console.log(foo);//{ abc: 'xyz', hhHH: 'hhh', xyz: 100, '[object Object]': 'obj2' }

this相关

嵌套函数

//非严格模式下
var obj = {
    test:function (){
        var self = this;
        console.log(this === obj); //true
        f();
        function f(){
            console.log(this === obj); //false
            console.log(self === obj); //true
            console.log(this === window);  //true 严格模式为undefined
            };
        }
    };
obj.test();

在object声明的上下文属于全局,浏览器下this指向window

var num=1;
let obj = {
    num :23,
    aaa:this.num,
}
console.log(obj.aaa);//输出为1

进一步箭头函数的this会指向上层,故用箭头函数定义对象方法时,this同样指向window

var num=1;
let obj = {
    fn:() =>{
        let num = 4
        console.log(this.num);
    }
}
obj.fn();//输出1

函数相关

1. 参数扩展与参数收集
参数扩展是将数组拆分

arr=[1,2,3];
fun(...arr);//即传入1, 2, 3

参数收集是将传入的多个参数合并成数组,类似于arguments构造机制

//函数声明中使用...
function fun(...value){...}
fun(1,2,3);//函数体中value为[1,2,3]

2. arguments
与命名参数一一对应,但内存位置不一样,修改其中一个另一个也会变化,但是如果有命名参数未传入,修改arguments无效

function fun(v1,v2,v3){
	arguments[0]=11111;
	console.log(v1);//11111
	v2=2222;
	console.log(arguments[1]);//2222
	arguments[2]="wowow"
	console.log(v3);//undefined
}
fun(1,3);

3. callee关键字可以将函数逻辑与函数名解耦

杂项

  • typeof的返回值是字符串
  • 字符串replace只会替换第一个,替换所有要用正则表达式 g
  • !!两个逻辑非可以将任何值转换成布尔类型
  • 位运算符优先级比关系操作符、相等操作符低,所以a|1==0相当于a|0即a,需要加括号成(a|1)==0
  • 1…toFixed()才是正确的,有俩点因为1.是1.0的省略
  • 交换a与b的多种方法
  • 基本类型调用包装类方法会先创建对象,再调用对应方法,后抛弃
  • 对于已经声明的变量进行解构赋值时,要非常小心。下面的示例中,首先用let对变量进行了声明,由于let和const声明的变量不能重复声明,在通过解构表达式赋值时,javascript解析器会将行首的{}解析为代码块,报语法错误。因此在行首加(),将其强制转化为表达式执行。
  • Array.prototype.sort()问题:如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 “Banana” 会被排列到 “cherry” 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 “80” 要比 “9” 要靠前。
  • 事件与消息队列&js引擎相关
  • delete
  • toString 和 valueOf
let obj={
    toString(){
        console.log('str');
        return 'A';
    },
    valueOf(){
        console.log('value');
        return {};
    }
}
obj+1//value str, 因为{}不能操作就会去尝试toString  

> (不会对返回值再次进行隐式转换的)

好题

const obj = {
  base: 42,
  add(...nums) {
    return nums.reduce((total, current) => current + total, this.base || 0);
  },
};

const f1 = obj.add.bind({ base: 3 }, [0]);
const f2 = obj.add.bind({}, 1);
const f3 = obj.add.bind({ base: 2 }, [1]);
console.log(f1(2), f2(2), f3(2));//203 3 212
  1. 链接
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arequitae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值