一. this绑定规则
函数调用位置决定了this的绑定对象,必须找到正确的调用位置判断需要应用下面四条规则中的哪一条。
1.1 默认绑定
看下面代码:
function foo() {
console.log(this.a);
}
var a = 1;
foo(); // 2调用foo的时候,this应用了默认绑定,this指向了全局对象,但是在严格模式下,那么全局对象将无法进行默认绑定,因此this会绑定到undefined
function foo() {
‘use strict‘;
console.log(this.a);
}
var a = 1;
foo(); // TypeRrror: this is undefined严格模式下与 foo() 的调用位置无关:
function foo() {
console.log( this.a );
}
var a = 2;
(function(){
"use strict";
foo(); // 2
})();
1.2 隐式绑定
另一条需要考虑的规则是调用位置是否有上下文对象
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2但是无论是直接在 obj 中定义还是先定义再添加为引用属性, 这个函数严格来说都不属于 obj 对象,然而, 调用位置会使用 obj 上下文来引用函数, 因此你可以说函数被调用时 obj 对象“ 拥有” 或者“ 包含” 它
对象属性引用链中只有最顶层或者说最后一层会影响调用位置。 举例来说:
function foo() {
console.log(this.a);
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 421.2.1 隐式丢失
一个最常见的 this 绑定问题就是被隐式绑定的函数会丢失绑定对象, 也就是说它会应用默认绑定, 从而把 this 绑定到全局对象或者 undefined 上, 取决于是否是严格模式,
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性
bar(); // "oops, global"虽然 bar 是 obj.foo 的一个引用, 但是实际上, 它引用的是 foo 函数本身, 因此此时的 bar() 其实是一个不带任何修饰的函数调用, 因此应用了默认绑定。在js内置函数中如setTimeout也是如此:
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a 是全局对象的属性
setTimeout(obj.foo, 100); // "oops, global"和下面伪代码类似:
function setTimeout(fn, delay) {
// 等待 delay 毫秒
fn(); // <-- 调用位置!
}1.3.显示绑定
call(...),apply(...)可以指定this的绑定对象(前者接收多个参数如call(this, param1, param2, param3...),后者接受一个或两个参数apply(this, [...]))
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
foo.call(obj); // 2通过 foo.call(..), 我们可以在调用 foo 时强制把它的 this 绑定到 obj 上。 如果你传入了一个原始值( 字符串类型、 布尔类型或者数字类型) 来当作 this 的绑定对 象, 这个原始值会被转换成它的对象形式( 也就是 new String(..)、 new Boolean(..) 或者 new Number(..))。 这通常被称为“ 装箱”。
1.3.1 硬绑定
function foo() {
console.log(this.a);
}
var obj = {
a: 2
};
var bar = function() {
foo.call(obj);
};
bar(); // 2
setTimeout(bar, 100); // 2
// 硬绑定的 bar 不可能再修改它的 this
bar.call(window); // 2我们创建了函数 bar(), 并在它的内部手动调用 了 foo.call(obj), 因此强制把 foo 的 this 绑定到了 obj。 无论之后如何调用函数 bar, 它 总会手动在 obj 上调用 foo。 这种绑定是一种显式的强制绑定, 因此我们称之为硬绑定。创建一个 i可以重复使用的辅助函数:
function foo(something) {
console.log(this.a, something);
return this.a + something;
}
//简单的辅助绑定函数
function bind(fn, obj) {
return function() {
return fn.apply(obj, arguments);
};
}
var obj = {
a: 2
};
var bar = bind(foo, obj);
var b = bar(3); // 2 3
console.log(b); // 5由于硬绑定是一种非常常用的模式, 所以在 ES5 中提供了内置的方法 Function.prototype.bind, bind(..) 会返回一个硬编码的新函数, 它会把参数设置为 this 的上下文并调用原始函数
1.3.2 api调用的“上下文”
function foo(el) {
console.log(el, this.id);
}
var obj = {
id: "awesome"
};
// 调用 foo(..) 时把 this 绑定到 obj
[1, 2, 3].forEach(foo, obj);
// 1 awesome 2 awesome 3 awesome这些函数实际上就是通过 call(..) 或者 apply(..) 实现了显式绑定, 这样你可以少些一些代码。
1.4. new绑定
在 JavaScript 中, 构造函数只是一些 使用 new 操作符时被调用的函数。 它们并不会属于某个类, 也不会实例化一个类。 实际上, 它们甚至都不能说是一种特殊的函数类型, 它们只是被 new 操作符调用的普通函数而已。使用 new 来调用函数, 或者说发生构造函数调用时, 会自动执行下面的操作:
1. 创建( 或者说构造) 一个全新的对象
2. 这个新对象会被执行 [[ 原型 ]] 连接
3. 这个新对象会绑定到函数调用的 this
4. 如果函数没有返回其他对象, 那么 new 表达式中的函数调用会自动返回这个新对象
二. 优先级
毫无疑问, 默认绑定的优先级是四条规则中最低的,来看看隐式绑定和显示绑定
function foo() {
console.log(this.a);
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3,
foo: foo
};
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call(obj2); // 3
obj2.foo.call(obj1); // 2显式绑定优先级更高, new 绑定和隐式绑定的优先级谁高谁低:
function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo
};
var obj2 = {};
obj1.foo(2);
console.log(obj1.a); // 2
obj1.foo.call(obj2, 3);
console.log(obj2.a); // 3
var bar = new obj1.foo(4);
console.log(obj1.a); // 2
console.log(bar.a); // 4可以看到 new 绑定比隐式绑定优先级高。 但是 new 绑定和显式绑定谁的优先级更高呢?
function foo(something) {
this.a = something;
}
var obj1 = {};
var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2
var baz = new bar(3);
console.log( obj1.a ); // 2
console.log( baz.a ); // 3bar 被硬绑定到 obj1 上, 但是 new bar(3) 并没有像我们预计的那样把 obj1.a 修改为 3。 相反,new 修改了硬绑定( 到 obj1 的) 调用 bar(..) 中的 this。 因为使用了 new 绑定, 我们得到了一个名字为 baz 的新对象, 并且 baz.a 的值是 3。之所以要在 new 中使用硬绑定函数, 主要目的是预先设置函数的一些参数, 这样在使用 new 进行初始化时就可以只传入其余的参数。 bind(..) 的功能之一就是可以把除了第一个 参数( 第一个参数用于绑定 this) 之外的其他参数都传给下层的函数( 这种技术称为“ 部 分应用”, 是“ 柯里化” 的一种)。 举例来说:
function foo(p1, p2) {
this.val = p1 + p2;
}
//之所以使用 null 是因为在本例中我们并不关心硬绑定的 this 是什么
// 反正使用 new 时 this 会被修改
var bar = foo.bind(null, "p1");
var baz = new bar("p2");
baz.val; // p1p2本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
javascript 运算符优先级,是描述在计算机运算计算表达式时执行运算的先后顺序。 先执行具有较高优先级的运算,然后执行较低优先级的运算。例如,我们常说的先执行相乘和除,再执行加减运算。
css的选择器是有权重(即优先级)的,在不同选择器的样式出现冲突时候,会采用权重高的选择器设置样式,而优先级不仅仅只是:“行间>内部>外部、ID>class>元素”。css优先级到底是怎么计算的呢?
这是一篇基础的文章,主要介绍css中的三大特性:css继承性、css层叠性、css优先级
css样式的继承性:给父元素设置一些属性,子元素也可以使用。应用场景:一般用于设置网页上的一些共性信息,例如网页的文字颜色,字体,文字大小等内容。优化代码,降低工作量
优先级就是分配给指定的 CSS 声明的一个权重,它由 匹配的选择器中的 每一种选择器类型的 数值 决定。而当优先级与多个 CSS 声明中任意一个声明的优先级相等的时候,CSS 中最后的那个声明将会被应用到元素上。
css3和css有什么区别?首先css3是css(层叠样式表)技术的升级版本,而css是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。然后是内容上css3主要包括盒子模型、列表模块
如果一个属性通过两个相同选择器设置到同一个元素上,相同的属性就会出现冲突,那么这个时候一个属性就会将另一个属性层叠掉,采用的是就近原则
UI产生交互的根本原因是各种事件,这也就意味着事件与更新有着直接关系。不同事件产生的更新,它们的优先级是有差异的,所以更新优先级的根源在于事件的优先级。一个更新的产生可直接导致React生成一个更新任务,最终这个任务被Scheduler调度
很多刚学CSS的朋友都听过这样的说法:行内样式权重是1000,ID选择器是100,类选择器是10,元素选择器是1。那么问题来了:20个类选择器能不能超过1个ID选择器呢?
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!