this指向
this是JavaScript语音的关键字。他代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,随着函数使用场合的不同,this的值会发生变化,指向是不确定的,也就是说可以动态改变。但是有一个总的原则,那就是this指向的是调用函数的那个对象。
window.onload = () => {
function fn() {
console.log(this); //window
}
fn();
function fn() {
"use strict";
console.log(this); //undefined
}
fn();
/**
* 在非严格模式下,未绑定的 this 默认指向全局对象 (window 或 global)。
* 而在严格模式下,this 不再自动指向全局对象,而是 undefined
*/
//内置函数this默认指向Window
function fn() {
console.log(this);//window
}
setTimeout(fn, 1000);
//回调函数this默认指向Window
function fn(v) {
console.log(v);
console.log(this);//window
}
function fn2(callback, value) {
callback(value);
}
fn2(fn, "hello");
//函数在数组中
function fn() {
console.log(this);
}
var arr = [fn, 2, 3, 4, { id: 3 }];
arr[0](); //[ [Function: fn], 2, 3, 4, { id: 3 } ]
var f = arr[0];
f(); //window
//函数在object对象中
function fn() {
console.log(this);
}
var obj = {};
obj.name = "xp";
obj.init = fn;
obj.init(); //{ name: 'xp', init: [Function: fn] }
//在构造函数中
//构造函数定义
function Person(name, age) {
this.name = name;
this.age = age;
console.log(this);
this.sayHello = function () {
console.log(this);
console.log(this.name);
};
}
//实例化
var jack = new Person("jack", 20);
jack.sayHello();
//创建新的实例,通过new操作符,经历一下步骤:
//1、创建新对象
//1、将构造函数作用域赋给这个新对象
//3、执行构造函数
//4、返回新对象
};
函数的默认作用域可以修改
call()、apply()、bind()用于改变函数内部this的值
var id = 1;
function fn() {
console.log(this.id);
}
fn();
var item = {id:888}
item.action = fn;
item.action();//888
fn.apply(item);//888 fn中的this指向了item
fn.call(item);//888
var a = "global";
var obj2 = {
a: 666,
action: fn,
};
obj2.action.apply(window,"vvv",4444);//this指向Window
apply和call的区别:传递参数的方式不同
var a = "global";
var fn = function fn(titile,value){
return `${this.a}-${titile}-${value}`
}
fn.call(obj,"call",1);//传参
fn.apply(obj,["Call",2]);//以数组的方式进行传参
//bind的使用:bind用于创建一个新的函数,该函数的上下文绑定到指定的对象,但并不会立即执行。
//bind:返回新的函数,这个新的函数不能再次改变作用域
var id =1;
function fn (){
console.log(this.id);
}
var item = {
id:888
}
fn.bind(item)();//相当于var f = fn.bind(item);然后执行f()
/********扩展*********** */
var n = 200;
var obj = {
n: 1,
render: function () {
this.n += 1;
console.log(this.n);
},
};
setInterval(obj.render,1000);//window
setInterval(obj.render.bind(obj),1000);//obj,obj.render.bind(obj)作用域不会改变
var length = 100;
function f1() {
console.log(this.length);
}
var obj = {
length: 10,
f2: function (f1) {
f1();//f1执行的时候,没有明确指明调用者,调用者还是Window
arguments[0]();//arguments是可变参数,arguments是一个数组,arguments[0]第一个元素是f1方法,
// 数组中的方法的作用域是数组,所以此时console.log(this.length)打印的是数组长度
},
};
obj.f2(f1, 1);//100,2
事件冒泡
<body>
<div class="div1">
div1
<div class="div2">
div2
<div class="div3">
div3
</div>
</div>
</div>
</body>
function f(name) {
return document.querySelector(name);
}
f(".div1").onclick = function () {
console.log("div1");
};
f(".div2").onclick = function () {
console.log("div2");
};
f(".div3").onclick = function (e) {//event对象
console.log("div3");
e.stopPropagation();//使用e.stopPropagation()对事件冒泡进行阻止
};
Event事件对象
阻止事件冒泡:e.stopPropagation()对事件冒泡进行阻止
Event事件对象
event.target或者event.currentTarget
event.target:事件发生源
event.currentTarget:绑定事件的元素
两者的区别:div3点击,但是可能没有绑定onclick事件,由于事件冒泡,div2绑定了onclick事件,这时候事件源target是div3,
事件currentTarget是div2
事件委托
把一个元素的响应时间委托到其他元素上执行
<ul id="list">
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>var list = document.getElementById("list");
var li = list.getElementsByTagName("li");
for (let index = 0; index < li.length; index++) {
const element = li[index];
element.onclick = function () {
this.style.color = "red";
};
}
//上面需要每一个节点进行注册事件,下面直接将事件注册给父元素
var list = document.getElementById("list");
list.onclick = function (e) {
if (e.target.nodeName === "LI") {
e.target.style.color = "red";
}
};
创建对象的方式
原型
用原型实例指向创建对象的类,使用于创建新的对象的类的共享原型的属性与方法
可以给构造函数对象定义一个原型对象,这个原型对象能够继承给所有被new创建出来的对象上
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.msg = "hello"; //在原型对象上添加任意属性
Person.prototype.action = function () {
console.log(`${this.name}~${this.msg}`);
};
var p = new Person("xp", 777);
console.log(p); //{ name: 'xp', age: 777 }
console.log(p.msg); //直接获取原型上的属性,如果构造函数有这个属性,就不去原型上查找
console.log(p.action()); //直接获取原型上的方法
哪些对象拥有原型对象?
JS对象分为2种,普通对象Object和
prototype是函数有的属性
普通对象和函数对象的区别:凡是通过new Function创建的对象都是函数对象,其他都是普通对象(通常通过Object创建),可以通过typeof来判断
普通对象(Object):
1、使用字面量定义:var obj = {};
2、
使用构造函数定义:var obj = new Object();
3、
使用Object.create()
方法:var obj = Object.create(null);
函数对象(Function):
1、使用函数声明定义:function func() {}
2、
使用函数表达式定义:var func = function() {};
3、
使用Function
构造函数定义:var func = new Function();
function f() {}
typeof f;//function,函数对象,这个可以通过new Function()来创建
var o = {}
typeof o;//普通对象:object
function F() {}
var o1 = new F();
typeof o1;//普通对象:object
1、每一个函数对象都有一个prototype属性,但是普通对象是没有的;prototype下面又有个constructor,指向这个函数。
2、每个对象都有一个名为__proto__的内部属性,指向它所对应的构造函数的原型对象,原型链基于__proto__;
function Cat(name, color) {
this.name = name;
this.color = color;
}
Cat.prototype.type = "animal";
Cat.prototype.eat = function () {
console.log("吃老鼠");
};
var Jack = new Cat("jack", "white");
var Tom = new Cat("tom", "black");
typeof Jack.constructor;//Jack被谁构造出来的,也就是Cat的函数对象
//通过普通对象修改原型对象的值
Jack.__proto__.type = "888";
Tom.type ;//888
原型链
/************************原型链******************************* */
function Animal() {
this.type = "animal";
this.hobby = ["吃", "睡"];
}
Animal.prototype.xyz = "xyz";
function Cat(name, color) {
this.name = name;
this.color = color;
}
Cat.prototype = new Animal(); //通过原型对象让两个对象产生关系
var Jack = new Cat("jack", "white");
var Tom = new Cat("tom", "black");
Jack.type; //animal
Jack.xyz; //xyz
Jack.__proto__.hobby[1] = "玩"; //修改原型对象的值
Jack.__proto__.__proto__.xyz = "999";