js高级
箭头函数
正常函数
function get() {
console.log("10");
}
get(); //10
将函数赋值给变量
const get2 = function () {
console.log("20");
};
get2(); //20
箭头函数传参
只传递一个参数时,小括号可以省略
const get = a => {
console.log(a);
};
get("40"); //40
不传参或传一个以上时不能省略小括号
const get = (a, b) => {
console.log(a, b);
};
get(1, 2); //1 2
返回值简写
当返回值只有一行时,大括号可以省略,不能写return,计算结果直接返回
const arr = () => 123 + 1; //代码不能换行
console.log(arr()); //124
当返回值为对象时,应该给大括号外面加一个小括号,否则大括号会被读取为函数结构
const arr2 = () => ({ name: "张三" });
console.log(arr2()); // { name: "张三" }
错误示范
错误原因:不传参或传参一个以上时,小括号不能省略
const func = => console.log(123)
console.log(func()); //报错
默认值
传不传参数会出现不同的值,常规写法
function get(str) {
if (str === undefined) {
console.log("你好");
} else {
console.log(str);
}
}
get();
get("你不好");
定义函数的时候,可以给形参设置默认值
const get1 = (box = "默认值") => box;
传参如果没有实参,就使用默认值
const get1 = (box = "你好") => box;
console.log(get1());// 输出 你好
如果有对应的实参,就使用参数
const get1 = (box = "你好") => box;
console.log(get1(123)); //输出 123
默认值为数组时
当没有实参时,输出默认值
const getLength = (arr = []) => console.log(arr.length);
getLength(); // 0
当有传参时,输出对应的值
const getLength = (arr = []) => console.log(arr.length);
let list = ['a','b'];
getLength(list); //2
函数的传参
当未传参时,返回值为NaN
const num = (a, b) => a + b;
console.log(num()); // NaN
当实参等于形参时,值正常返回
const num = (a, b) => a + b;
console.log(num(3, 4)); // 7
当实参少于形参时,返回NaN,没有实参传入的形参为undefined
const num = (a, b) => a + b;
console.log(num(3)); //NaN
当实参多于形参时,正常返回,多余的实参没有形参接收,不参与计算
const num = (a, b) => a + b;
console.log(num(3, 4, 5));// 7
结论:函数中的形参可以少于实参的数量,但不能多于
解构
数组解构
常规获取数组中数据的方法
const arr = ["a", "b", "c"];
// 常规获取数组数据方法
// const str1 = arr[0]
// const str2 = arr[1]
// console.log(str1,str2) //a b
数组解构
const arr = ["a", "b", "c"];
const [str1, str2] = arr;//['a','b','c']
console.log(str1, str2); // a b
交换变量
常规交换变量
let num1 = 100;
let num2 = 200;
let temp = num1; // 先把num1的值100赋值给临时变量
num1 = num2; //再将num2的值赋值给num1
num2 = temp; //最后将临时变量的值赋值给num2 完成交换
console.log(num1, num2); // 200 100
解构交换变量
// 声明数组,然后使用解构
let a = 100;
let b = 200;
// let arr2 = [100,200]
[b, a] = [a, b]; // [b,a] = arr2
console.log(a, b); // 200 100
对象解构
常规方法
const obj = { uname: "张三", age: "18" };
const uname = obj.uname;
const age = obj.age;
console.log(uname,age); // 张三 18
使用解构
const obj = { uname: "张三", age: "18" };
const { uname, age } = obj;// { uname: "张三", age: "18" };
console.log(uname, age); // 张三 18
函数参数解构
常规方法
function fn(option) {
// 传入对象
console.log(option.username);
}
fn({ username: "八戒" });
使用解构
function fn({ username }) { //解构要加大括号
// 传入对象
console.log(username);
}
fn({ username: "八戒" });
对象简写
对象简写---如果对象名和变量名一致的写法
const username = '悟空';
const skill = '72';
const obj = {
username,
skill,
};
函数简写
const uname = "悟空";
// 函数简写
const obj2 = {
uname,
say() {
console.log("函数简写");
},
};
console.log(obj2.say); //函数简写
拓展运算符||剩余运算符
剩余运算符可以获取剩余所有数据
获取数组剩余数据
let arr = ["a", "b", "c", "d"];
const [array1, array2, ...list] = arr;
console.log(list); // ['c','d']
数组合并
const list1 = [1, 2, 3];
const list2 = [1, 2, 3];
const list3 = [...list1, ...list2];
console.log(list3);
获取对象剩余数据**
let obj = {
a: 1,
b: 2,
c: 3,
d: 4,
};
const { a, b, ...obj2 } = obj;
console.log(obj2); // {c:3,d:4}
对象合并
对象合并,同名的属性名后面的会覆盖前面的
const object1 = { username: "悟空" };
const object2 = { username: "八戒", height: 150 };
const object3 = { ...object1, ...object2 };
console.log(object3); // {username: '八戒', height: 150}
// 下面的八戒和上面的悟空同名,在后面的同名覆盖前面的属性值
当函数中的值不确定时,可以使用剩余运算符
function cala(...params) {
// params 会获取到所有的传参,将这些参数存到一个数组中
console.log(params);
}
cala(); // []
cala(1); //[1]
cala(1, 2); //[1,2]
cala(1, 2, 3); // [1,2,3]
js数据类型
值类型 / 简单数据类型
数字 , 字符串 , 布尔值 , undefined , null
简单数据类型变量值改变,其他值不变
let a =1 ;
let b = a;
// b a 的一份复制 两个值 一样 但是两个数据是完全独立!
b=10;
// a 不会发生变化
console.log(a);
引用类型 / 复杂数据类型
数组 , 对象 , 函数
const obj = { username: '悟空', height: 100 };
const newObj=obj;
newObj.username = '八戒';
//当修改新对象时,其他对象也会发生改变
console.log(obj); // { username: '八戒', height: 100 }
复制引用类型
const list = ['a', 'b'];
// const newList = list; //
const newList = [...list];
newList.push('c');
//当改变新数组时,其他数组不会发生改变
console.log(list); // ['a','b']
数组方法
for 和 foreach有什么区别 1 都是循环 2 for循环可以被中断 但是 foreach不可以!!
**数组方法map() **
遍历旧数组然后符合条件的元素返回一个新数组
map中回调函数可以有两个参数
1.元素本身
2.元素下标
数组的一个方法 也会遍历 数组 接收一个函数
const arr = ['a', 'b', 'c'];
const newArr = arr.map(function (value) {
return `<li>${value}</li>`;
});
console.log(newArr);
结合箭头函数
const arr = ['a', 'b', 'c'];
const newArr = arr.map(value => `<li>${value}</li>`);
数组方法filter() 过滤
filter 检测数组元素,并返回符合条件所有元素的数组
filter会遍历每个元素,回调函数有两个参数,元素和下标
必须要满足return true或false 表示当前元素是否满足条件
const arr = [1,3,5,7,9];
const newArr = arr.filter(function(value){
if(value > 3){
return true;
} else {
return false;
}
})
console.log(newArr) // [5,7,9]
简写
const arr = [1,3,5,7,9];
//const newArr = arr.filter(value => value > 3 ? true : false)
const newArr = arr.filter(value => value > 3) //当value大于3时直接返回true,否则返回false
数组方法every()
检测数组中每个元素是否都符合条件
全部都符合,返回 true 否则 返回 false
every 检测数组中的每一个元素是否都符合条件
every会接收一个回调函数
回调函数,接收两个参数
1.元素本身 item
2.元素下标 index
some是找到一个符合条件就返回,every是检测全部是否符合条件
const names = ['黄圣飞', '梁聪', '王锦双', '韦嘉敏', '刘雅琴'];
// 判断一下 上面所有同学的名称 是不是 长度 都是大于2 (每一个)
const result = names.every(function (value) {
console.log(value);
if (value.length > 2) {
return true;
} else {
return false;
}
});
//箭头函数简写
const result = names.every(value => value.length > 2) // 所有人的名字长度大于2就返回true
if(result){
console.log('名字长度全部大于2')
}else {
console.log('有名字长度不大于2的')
}
every 对空数组也会直接返回true
数组方法some()
数组中只要有一个符合要求就返回true
数组方法some会遍历数组,检测数组中是否有符合条件的元素,找到一个满足条件的就不再遍历
some会接收一个回调函数
回调函数,接收两个参数
1.元素本身
2.元素下标
some就会返回寻找的结果
const arr = [
'健康',
'健康',
'健康',
'健康',
'健康',
'健康',
'健康',
'健康',
'健康',
'健康',
];
// some方法来判断 队列 是不是有危险
const result = arr.some((value) => value === '中招');
if (result) {
console.log('有危险');
} else {
console.log('健康');
}
数组方法find
find 寻找符合要求的一个数组元素,返回元素本身
回调函数有两个参数,元素本身和元素下标
返回了true表示找到了,就不会往下遍历 找不到返回undefined
const arr = [
{ username: '悟空', height: 70 },
{ username: '八戒', height: 60 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
];
const obj = arr.find((value) => {
console.log(value);
if (value.height === 60) {
return true;
} else {
return false;
}
});
console.log(obj); // {username: '八戒', height: 60}
简写
const obj = arr.find((value) => value.height === 60);
console.log(obj);
数组方法findIIndex
找到数组中符合条件的元素的下标,
找到了就返回true,如果没找到返回-1
功能相对indexof来说强大一些,可用于数组中复杂数据类型的查找
const arr = [
{ username: '悟空', height: 70 },
{ username: '八戒', height: 60 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
{ username: '龙马', height: 30 },
];
const index = arr.findIndex((value) => value.height === 660);// 找不到就返回 -1
console.log(index); // -1
arrr.splice(index,1)
console.log(arr)
数组方法includes()
判断一个数组是否包含一个指定的值
或者判断一个字符串里是否包含某个字符
包含就返回true,不包含就返回false
const arr = ['a', 'b', 'c', 'd'];
const result = arr.includes('e');
console.log(result); //false
数组方法indexof
类似 findIndex indexOf 搜索数组中的元素,并返回它所在的位置(元素的下标) 一般是简单数据使用
找到了 就返回元素的下标,没有找到了 返回 -1
const arr = ['a', 'b', 'c', 'd'];
const index = arr.indexOf('h');
console.log(index); //-1
数组方法join 转字符串
join 方法是将数组元素转字符串,常和map连用
const arr = ['a', 'b', 'c'].map((value) => `<li>${value}</li>`);
// const arr = ['<li>a</li>', '<li>b</li>', '<li>c</li>'];
const result = arr.join('');
console.log(result); // <li>a</li><li>b</li><li>c</li> 转成字符串了
数组方法for of
遍历输出每一个元素的值
let arr = [1,2,3,4]
for(let val of arr){
console.log(val) // 1 2 3 4 //输出每一个值
}
数组方法forEach
数组自带的一个遍历方法
forEach 数组方法,可以对数组做遍历,可以接收一个回调函数,每一次遍历自动执行回调函数
forEach可以接收两个参数,第一个是遍历的元素item,第二个是遍历元素的下标index
for可以被break打断,forEach不能被break打断,会报错
let arr = [1,2,3,]
arr.forEach(function(item,index){
console.log(item) // item 是数组的值
console.log(index) // index 是数组值所对应的下标
})
const arr = [1, 2, 3, 4];
arr.forEach(function (item, index) {
console.log(item, index);
});
console.log("-----------------------------------------");
// 箭头函数简写
arr.forEach((item, index) => console.log(item, index));
set对象
1 Set 是一个对象 不会存放重复数据
2 数组转成 set对象 const set = new Set([])
3 set对象 转成 数组 const arr=[...set]
4 set对象 添加数据 使用add方法
const list = [1, 4, 5, 6, 7];
const set = new Set(list); // 将数组转成对象
set.add(1);
set.add(2);
set.add(2);
set.add(2);
set.add(2);
set.add(2);
set.add(2);
set.add(3);// 给对象添加元素 , set不会存放重复数据
const arr = [...set]; // 用剩余运算符将对象转换为数组
console.log(arr); // [1, 4, 5, 6, 7, 2, 3]
面向对象
一种编程行业通用的写项目级
的代码的思维,引导我们如何编写高质量的代码,万物皆对象 - 看待事物的角度,(属性:数据,行为:动作(方法))。代码特点是封装和继承
创建对象
字面量
不适合创建多个同样类型的对象的场景
const obj ={ name:"悟空",height:100,age:5000};
工厂函数
可以批量创建对象
function fn(name, age) {
return { // 不return会返回undefined
name,
age,
};
}
const obj1 = fn("悟空", 600);
const obj2 = fn("八戒", 1800);
console.log(obj1);
console.log(obj2);
构造函数es5
1.本质就是一个函数
2.命名,首字母建议大写
3.作用,必须用来new 创建对象 否则 没有意义 undefined
4.实例 p变量就是Person的实例
// 构造函数其实就是创建了一种创建对象的模板
// 通过一个构造函数创建出来的实例的属性一模一样
function Person() {
// this指的就是后面创建出来的实例
this.username = "八戒";
}
Person(); // 普通函数
const p1 = new Person(); // new了的就是构造函数 p就是Person的实例
const p2 = new Person(); // new了的就是构造函数 p就是Person的实例
const p3 = Person(); // 没有使用new来创建对象,返回undefined
console.log(p1);
console.log(p2);
console.log(p3);
function Person(name, height) {
// 每个实例属性名都一样,值为实例的传参
this.username = name;
this.height = height;
}
const p1 = new Person("八戒", 150);
const p2 = new Person("悟空", 180);
console.log(p1);
console.log(p2);
构造函数的弊端
-
调用方法时,没一个方法都会占据一份内存
方法和函数写在构造函数中都要在见面加this,否则实例找不到对应的属性和方法
function Person(){ this.say: function(){ console.log('这个是say方法') } } const p1 = new Person() const p2 = new Person() p1.say() p2.say() console.log(p1.say === p2.say) // false // 两个say方法不是同一个地址
2.将say方法在构造函数外面设置一个函数,然后在构造函数里赋值
这种可以解决浪费内存的问题,但是会造成污染全局变量的问题
// 提前将say 声明好
function say() { // 污染全局变量
console.log(this.name);
}
function createStudent(name, age) {
this.name = name;
this.age = age;
this.say = say
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // true
构造函数,原型,实例
1.构造函数 父亲 只能有一个
2.实例 儿子 可以有多个
3.原型 DNA 父亲原型上面有的儿子原型可以继承
将方法直接挂载到构造函数的原型上,既没有浪费内存,也没有造成全局变量污染
// 在构造函数内部只会定义一些非函数类型的属性
function Person(name, age) {
this.name = name;
this.age = age;
}
// 只要是 方法和函数都定义在原型上
Person.prototype.say = function () {
console.log("这个是say方法");
};
Person.prototype.show = function () {
console.log("这个是show方法");
};
// 原型上的方法可以使用this来调用构造函数中的属性
Person.prototype.toggle = function () {
console.log(this.age);
};
const p1 = new Person("八戒", 800);
const p2 = new Person("悟净", 1800);
const p3 = new Person("净坛使者", 1800);
console.log(p1);
console.log(p2);
console.log(p3);
console.log(p1.say === p2.say);
p1.say();
p1.show();
p1.toggle();
在构造函数内部只会定义一些非函数类型的属性
只要是 方法和函数都定义在原型上
原型上的方法可以使用this来调用构造函数中的属性
function createStudent(name, age) {
this.name = name;
this.age = age;
}
// 将刚才的全局函数say 直接挂载到 构造函数的原型上 即可
// prototype 是个对象 每一个构造函数都会内置有的. 我们称之为原型
createStudent.prototype.say = function () {
console.log(this.name);
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // true
原型
- 原型的单词是
prototype
, 原型的这个名字是行业内共同认可的名字。 - 原型本质是一个对象,理解为
JavaScript
自动帮我们添加的 - 原型是
JavaScript
自动帮我们在定义构造函数
的时候添加的 - 所有构造函数的实例,共享一个原型
- 原型上一般是挂载函数
原型链继承
利用代码的能力实现 面向对象的特性 封装 和 继承
继承
1 父亲有的 儿子什么都不用做 直接就拥有
父亲 构造函数 儿子 构造函数
2 儿子要继承父亲
属性(this里面一坨)
方法 原型上定义的方法
// 属性写在构造函数内
function Parent(name, age) {
this.name = name; // this指向obj // 规则,谁调用了方法,this就指向谁
this.age = age;
}
// 方法定义在原型上
Parent.prototype.say = function(){
console.log("这是父亲的方法");
};
function Son(name, age, height) {
//call将指向父构造函数里的借调给子构造函数 继承父亲的属性
Parent.call(this, name, age);
this.height = height;
}
//单个赋值
Son.prototype.say = Parent.prototype.say;
const son = new Son("八戒", 1800, 150); //实例
console.log(son);
call可以借调或者说是修改this的指向
const obj = {
say(a, b, c) {
this.a = a;
this.b = b;
this.c = c;
},
};
const newObj = {};
obj.say.call(newObj, 10, 20, 30);
console.log(newObj); // {a: 10, b: 20, c: 30}
对象新增属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0,maximum-scale=1,minimum-scale=1,user-scalable=no"
/>
<title>06-对象新增属性.html</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
</head>
<body>
<script>
const obj = {
say() {
// this 指向谁 obj
// obj.username="八戒";
// this.username="八戒";
this.a = 1;
this.b = 2;
this.c = 3;
},
};
// 给对象添加属性
// obj.username = '八戒';
// 调用say方法
obj.say();
// 借用this的指向调用对象中的方法给对象增加属性
console.log(obj); // {a: 1, b: 2, c: 3, say: ƒ}
</script>
</body>
</html>
构造函数原型标准继承
<script>
//父构造函数属性
function Parent(name, color, height, weight) {
this.name = name;
this.color = color;
this.height = height;
this.weight = weight;
}
//子构造函数
function Son(name, color, height, weight, money) {
Parent.call(this, name, color, height, weight);
this.money = money;
}
Parent.prototype.say = function () {
console.log('这个是父亲的行为');
};
Parent.prototype.say1 = function () {
console.log('这个是父亲的行为');
};
Parent.prototype.say2 = function () {
console.log('这个是父亲的行为');
};
Parent.prototype.say4 = function () {
console.log('这个是父亲的行为');
};
// 累,每一个都要赋值
// Son.prototype.say = Parent.prototype.say;
// 引用类型,赋值的是同一个地址,一变都变
// Son.prototype = Parent.prototype;
// 用拓展运算符
Son.prototype = { ...Parent.prototype };
// 我只想给儿子新增一个方法 不希望父亲有!!!
Son.prototype.a = function () {
console.log('这是儿子的新增方法')
};
// const s = new Son(1, 2, 3, 4, 5);
// console.log(s);
console.log(Parent.prototype);
console.log(Son.prototype); // 父亲的方法和儿子的方法指向的不是一个地址
</script>
案例-- 封装
<script>
function Div(d) {
this.div = document.createElement("div");
this.div.innerText = d;
}
function Img(src) {
this.img = document.createElement("img");
this.img.src = src;
}
Div.prototype.appendBody = function () {
document.body.appendChild(this.div);
};
Img.prototype.appendBody = function () {
document.body.appendChild(this.img);
};
const divElement = new Div("这个是div的内容");
const imgElement = new Img("./1629b0bdb08b467c6de909aee6fe9d11.png");
setTimeout(() => {
divElement.appendBody();
}, 1000);
setTimeout(() => {
imgElement.appendBody();
}, 3000);
</script>
案例-- 以继承的思想来写
<script>
// 先创建一个父构造函数封装
function Element(a) {
//将需要创建的标签传参,根据不同的传参创建不同的标签
// 创建标签
this.dom = document.createElement(a);
}
// 父构造函数原型
Element.prototype.appendBody = function () {
// 将创建好的标签插入到body中
document.body.appendChild(this.dom);
};
// -------------------------------------------------------------------
// 儿子1
function DivElement(d) {
// 将实例内容传参
// 继承父构造函数属性
Element.call(this, "div"); //将div作为参数传给父构造函数
this.dom.innerText = d;
}
// 儿子1继承父构造函数原型上的方法
DivElement.prototype = { ...Element.prototype };
// -------------------------------------------------------------------
// 儿子2
function ImgElement(src) {
// 将实例内容传参
// 继承父构造函数属性
Element.call(this, "img"); //将img作为参数传给父构造函数
this.dom.src = src;
}
// 儿子2继承父构造函数原型上的方法
ImgElement.prototype = { ...Element.prototype };
// ------------------------------------------------------
// 儿子1实例
const div = new DivElement("这是一个div");
// 儿子2实例
const img = new ImgElement("./1629b0bdb08b467c6de909aee6fe9d11.png");
setTimeout(() => {
div.appendBody();
}, 1000);
// -------------------------------------------------------
setTimeout(() => {
img.appendBody();
}, 3000);
</script>
es6
es6的class语法
es5 普通的属性 写在this上 函数写在 原型上
es6 第一种写法,不接收参数
// class 类 es6写法
// 属性和方法直接写在class类中,方法可以在原型中直接被继承
class Person {
username = "悟空";
say() {
console.log("这是class类方法");
}
}
// 实例
const p1 = new Person();
console.log(p1);
es6 第二种写法,接收参数
<script>
class Person {
constructor(username, height) {
// 构造器,可以接收参数
this.username = username;
this.height = height;
}
}
const p1 = new Person("悟空", 180);
console.log(p1);
</script>
es6 的继承
extends 可以直接继承父类的属性和方法
如果子类继承了父类,还有自己的属性和方法,在子类中方法可以直接写,属性有两种写法
1.要不就不要写构造器,代码默认给子类加一个super方法,调来父类的构造器 属性写死,不能传参
2.如果要写构造器,要在构造器里调用一个方法super,super === 父类.call(this) 指的是父类的构造器
class Person {
constructor(username) { // 构造器
this.username = username;
}
say() {
console.log("这是父类的say方法");
}
}
class Son extends Person {
constructor(username, age) {
super(username); //指向父类构造器
this.age = age;
}
get() {
console.log("这是子类的get方法");
}
}
// 子类实例
const s = new Son("悟空", 500);
console.log(s);
案例
<script>
// 父类
class Element {
// 创建元素
constructor(e) {
this.dom = document.createElement(e);
}
// 方法
appendBody() {
document.body.appendChild(this.dom);
}
}
// 子类1
class DivElement extends Element {
constructor(content) {
super("div"); // 传参给父类构造器
this.dom.innerText = content;
}
}
// 子类2
class ImgElement extends Element {
constructor(src) {
super("img"); // 传参给父类构造器
this.dom.src = src;
}
}
// 子类1实例
const divElement = new DivElement("这个是div的内容"); //传参给子类构造器
// 子类2 实例
const imgElement = new ImgElement(
"./1629b0bdb08b467c6de909aee6fe9d11.png" // 传参给子类构造器
);
setTimeout(() => {
divElement.appendBody();
}, 1000);
setTimeout(() => {
imgElement.appendBody();
}, 3000);
</script>
检测数据类型
简单数据类型检测 typeof 不适合检测复杂数据类型
复杂数据类型检测 instanceof 检测实例是不是构造函数 的实例
// 简单数据类型检测 typeof 不适合检测复杂数据类型
console.log(typeof 1213); //number
console.log(typeof "abc"); //string
console.log(typeof true); //boolean
console.log(typeof []); //object
console.log(typeof {}); //object
console.log(typeof function () {}); // function
// 复杂数据类型检测 instanceof 检测实例是不是构造函数 的实例
function Person() {}
function Boll() {}
const p1 = new Person();
const b1 = new Boll();
console.log(p1 instanceof Person); // true
console.log(p1 instanceof Boll); // false
this指向
<script>
// 一般情况下 this指向 调用者 (谁调用代码 this 指向谁)
// const obj={
// username:"八戒",
// say(){
// console.log(this);
// }
// }
// obj.say();
// function say() {
// console.log(this);
// }
// say();// 指向谁 ???? window
// window.say();
// 我们在 全局中 通过function 来定义 函数 这个函数理解默认就添加到 window属性上!!
window.say = function () {
console.log(this);
console.log('say方法被调用');
};
say();
</script>
call apply bind之间的区别
call apply bind 三个都可以改变this的指向
call和apply可以之间调用
bind被调用时,不会触发原来的函数,而是会返回一个新的函数,需要用新函数去自己调用
call apply bind 的区别,传递参数的写法不同
<script>
/*
call-bind-apply
1 这三个 技术 都可以实现 修改this的指向
1 call 和 apply 直接调用
obj.say.call(newObj)
obj.say.apply(newObj)
2 bind被调用的时候 不会直接触发原来的函数 say 而是会返回一个新的函数 我们自己去调用新函数
2 call 和 apply 区别 传递参数的写法 不同!!
1 obj.say.call(newObj,1,2);
2 obj.say.apply(newObj,[1,2]);
3 (obj.say.bind(newObj))(1,2);
*/
const obj = {
username: '八戒',
say(a,b) {
console.log(this);
console.log(a,b);
},
};
const newObj = {
username: '悟空',
};
// obj.say();// obj
// obj.say.call(newObj);// newObj
// obj.say.apply(newObj); // newObj
// const newSay = obj.say.bind(newObj); // newObj
// newSay();
// (obj.say.bind(newObj))(); // newObj
// obj.say.call(newObj,1,2);// 传参
// obj.say.apply(newObj,[1,2]);// 传参 数组
(obj.say.bind(newObj))(1,2); // 之间调用时加括号可以传参
</script>
箭头函数 没有this指向 ,如果你的函数中 出现了this 慎用 箭头函数!!
很多的情况下 指向了window
// function say() {
// console.log(this);
// }
// const say=()=> console.log(this);
// const obj = {
// username: '八戒',
// say: () => {
// console.log(this);
// },
// };
// obj.say();
const button = document.querySelector('button');
button.addEventListener('click', () => {
console.log(this); // dom
});
原型链
<script>
/*
原型链 一层关系 多个对象 可以通过 原型 技术 层层的关联
prototype 构造函数点出来
__proto__ 实例点
*/
// const div=document.querySelector("div")
// console.dir(div)
function Person() {}
const p1 = new Person();
// console.log(Person.prototype === p1.__proto__);
p1._
</script>