执行顺序
var a = 1;
var b = 2;
let obj = {
a: 3,
b: 4,
getA: function () {
var a = 5;
setTimeout(function () {
console.log('this.a', this.a);
})
},
getB: function () {
var b = 6;
return function () {
console.log('this.b', this.b);
}()
}
}
obj.getA() // 1
obj.getB() // 2 // 立即执行
// 输出 2 1
作用域
let name = "张三"
let obj = {
name
}
console.log(obj.name); // 张三
获取数组的最值
let arr = [1, 2, 3, 4];
let max = Math.max(...arr);
console.log(max); // 4
let arr = [1, 2, 3, 4];
let max = Math.max.apply({}, arr);
console.log(max);
js的传参
js的传参分为值传递和引用传递,简单类型是值传递,复杂类型是引用传递,
函数内部对值传递不会影响外部,对引用传递改变会影响外部
function fn(o, val) {
o.b = 1;
val = 1;
}
var obj = { b: 0 };
var num = 0;
fn(obj, num);
console.log(obj, num); // {b:1} 0
匿名函数的this
匿名函数具有全局性,匿名函数的this指向window
var uname = "window";
var object = {
uname: "object",
fun: function () {
console.log(this.uname);
return function () {
console.log(this.uname);
};
},
};
object.fun()(); // object window
立即执行函数
1.立即执行函数如果有函数名
var a = 10;
(function a() {
a = 20; // 这里相当于修改函数名,无效
console.log(a); // 打印函数a [Function: a]
})();
// 2.立即执行函数没有函数名
(function () {
var a = 100; // 此时的a成为全局变量,挂在到window上!
console.log(a); // 100
})();
// 3. 普通函数变量无效 立即执行函数变量提升
function add() {
b = 2;
}
console.log(b); // b is not defined
function add() {
b = 2;
}
add()
console.log(b); // 2
(function () {
b = 2; b挂载到window上
})();
console.log(b); // 2
(function () {
var b = 2;
})();
console.log(b); // b is not defined
// 4. 函数提升大于变量提升
var add = 1;
function add() {
add = 2;
console.log(add);
}
add(); // add is not a function
// 将上面代码转换一下:函数提升大于变量提升 add()内部的变量是函数内部的,无关
// 变量提升
function add() {}
var add = undefined;
// 赋值阶段
function add() {
add = 2;
console.log(add);
}
add = 1;
// 调用阶段
add(); // add 已经被变成变量了,不是函数了
// 验证阶段
console.log(typeof add); // number
参数设置默认值
// 参数设置默认值
var a = 1;
function add(a = 2) {
console.log(a); //2
var a = 3;
console.log(a); //3
}
add();
console.log(a); //1
// 参数没有设置默认值
var a = 1;
function add(a) {
console.log(a); //88
var a = 3;
console.log(a); //3
}
add(88);
console.log(a); //1
// 参数多种形式
var a = 12;
function add(a = 1,b = function () {a = 3;console.log(a);}) { // 输出参数3
b();
console.log(a);// 输出参数1
var a = 10;
console.log(a); //10
}
add();
console.log(a); // 12
类
类不会变量提升,和let、const相似,存在暂时性死区
var a = 1;
function test() {
console.log(a); // 报错,作用域内的a,存在暂时性死区
class a { }
console.log(a); // class a{}
}
test();
除以0
任何数值除以0都会导致错误而终止程序执行,但是在 JavaScript 中,会返回出NaN,不影响后面程序
var num = prompt('请输入分母:')
try {
console.log('a');
value = 0 / num;
console.log('b');
}
catch (e) {
console.log('c');
}
finally {
console.log('d'); // a b d 不会去catch处理,因为不会报错
}
settimeout内部this指向window
解决settimeout内部this指向window的三种解决方案
- that = this
- call、apply、bind
function () {
setTimeout(function () {
this.disabled = true;
}.bind(this), 1000)
}
- 函数内包含箭头函数
function() {
setTimeout(() => {
this.disabled = true;
}, 1000)
}
NaN
只有set、Object.js、includes能正确识别NaN === NaN
NaN 相关:
NaN == NaN // false
NaN === NaN // false
// indexOf方法无法识别数组的NaN成员
[NaN].indexOf(NaN) // -1
// 向 Set 数据结构中加入值时认为NaN等于自身
let set = new Set();
set.add(NaN);
set.add(NaN);
console.log(set); // Set {NaN}
// Object.is()方法认为NaN等于NaN
Object.is(NaN, NaN) // true
+ 0 === -0 //true
Object.is(+0, -0) // false
// ES7中新增的数组实例方法,includes()方法认为NaN等于自身
[1, 2, NaN].includes(NaN) // true
做数值操作,null会转成0,undefined会转成NaN
console.log(Number(null)) // 0
console.log(Number(undefined)) // NaN
defineProperty
defineProperty定义的新的属性,默认配置项全是false,修改已经存在的配置项,默认会变成true
var obj = {
brand: '华为',
price: 1999
};
Object.defineProperty(obj, 'id', { value: 1 }) // d
// 新增的属性全是false { value: 1, writable: false, enumerable: false, configurable: false }
console.log(Object.getOwnPropertyDescriptor(obj, 'id'));
Object.defineProperty(obj, 'price', { configurable: false })
// 修改已经存在的属性,默认值会变成true,这时候又强制设置configurable的值
// { value: 1999, writable: true, enumerable: true, configurable: false }
console.log(Object.getOwnPropertyDescriptor(obj, 'price'));
console.log('①', Object.keys(obj).length); // 2
for (var k in obj) {
console.log('②', obj[k]); // ② 华为 ② 1999
}
obj.price = 999;
delete obj['price']
console.log('③', obj); // ③ { brand: '华为', price: 999 }
各种this输出问题
// 箭头函数
function test() {
this.flag = false;// === button.flag = false
this.change = () => // === button.change()
this.flag = true; // === button.flag = true 箭头函数的this由test决定,test的this是button
console.log(button.flag);
};
const button = new test(); // test做了构造函数,所以this指向button实例
button.change()
// 调用形式不同,this指向不同
var len = 117;
let func = {
len: 935,
showLen: function () {
console.log(this.len);
},
show: function () {
(function (cb) {
cb();//以【函数】的形式调用时,this指向window
})(this.showLen)
}
}
func.show(); // 117
func.showLen(); //935 以【方法】的形式调用时,this指向被调用的对象(这里是【func】)
window.value = 'v';
function fn() {
console.log(this.value);
}
function calIArrowFn() {
const arrowFn = () => {
console.log(this.value);
};
arrowFn();
}
function getArrowFn() {
const arrowFn = () => {
console.log(this.value);
};
return arrowFn;
}
const objA = {
value: 'a',
fn: fn
}
const objB = {
value: 'b',
fn: calIArrowFn
}
const objC = {
value: 'c',
fn: getArrowFn()
}
fn(); // v
objA.fn(); // a
objB.fn(); // b
objC.fn(); // v
指定原型链
指定原型链,只要有一方更改原型,2方都会受影响
function Father(age) {
this.age = age
}
function Son(age) {
Father.call(this);
}
Son.prototype = Father.prototype;
Father.prototype.getAge = function () { console.log(40); }
Son.prototype.getAge = function () { console.log(18); }
var father = new Father(40);
var son = new Son(18);
son.getAge(); // 18
father.getAge(); // 18
console.log(father); // Father { age: 40 }
console.log(son); // Father { age: undefined } age没有值,因为call的没有参数列表
js 的 || 和 && 运算规则
a || b
a是true,不用计算b,直接返回a
a是false,需要计算b,无论b是什么,返回b
a && b
a是true,需要计算b,无论b是什么,返回b
a是false,不用计算b, 返回a
|| 第一true,返第一,第一false,返第二
&& 第一true,返第二,第一false,返第一
var a = 4 >= 6 || true && 1 || false;
console.log(a); // 1
// 4 >= 6 =>false
// true && 1 =>1
// 原式变成 false || 1 || false
// false || 1 => 1
// 1 || false => 1
点运算符高于typeof
console.log(typeof ''.prototype); // undefined ''没有原型,只有函数才有prototype
console.log(typeof ''.__proto__); // object ''.__proto__是String
console.log(typeof ''.__proto__ === typeof ''.prototype); // false
isNaN
判断是否是非数值类型,但是比较恶心的是,在判断之前,会先进行类型转换,转成数值了,就返回false,说明是数值,无法转成的,就返回true,说明是非数值
console.log(isNaN(113)); // false
console.log(isNaN('113')); // false
console.log(isNaN('abc')); // true
console.log(isNaN(true)); // false
console.log(isNaN(false)); // false
svg
svg是html的一个分支
link属于html的范畴 @import属于css的范畴,只能加载css
link加载时并行加载的,加载完的先进行解析 script的加载是加载完一个之后,再加载另一个
css的百分比相对问题
参照父元素宽度的元素:padding margin width text-indent
参照父元素高度的元素:height
参照父元素属性:font-size line-height
特殊:relative,top(bottom) left(right)参照的是父元素的内容区域的高度与宽度,而绝对定位的时候参照的是最近的定位元素包含padding的高度与宽度(包含padding的宽度是clientWidth)
<style>
.div-content {
width: 200px;
height: 300px;
background-color: cadetblue;
/* font-size: 20px; */
}
.son-content {
/* width = 20px 相对父级宽度 */
width: 10%;
/* height = 20px 相对父级高度 */
height: 10%;
/* padding = 20px 相对父级宽度 */
padding: 10%;
/* margin = 10px 相对父级宽度 */
margin: 5%;
background-color: antiquewhite;
/* font-size = 18px 相对父级font-size */
font-size: 90%
}
</style>
width
width:就是width clientWidth = width + padding
offsetWidth = border + width + padding + 滚动条(如果有的话)
scrollWidth = clientWidth + 滚出屏幕外的宽度(如果有的话)