Giter Site home page Giter Site logo

-'s People

Contributors

product-nav avatar

Stargazers

 avatar

Watchers

 avatar

-'s Issues

初探javascript中的this

一.this到底是什么

当一个函数被调用时,会创建一个执行上下文,执行上下文的生命周期如下:

创建 { 生成变量对象,建立作用域链,确定this指向 } -----> 执行{ 变量赋值,函数引用,执行其他代码 } ----->执行完毕后出栈,等待被回收

我们需要消除对this的误会是,this既不指向函数自身也不指向函数的词法作用域。this就是执行上下文的一个属性,它指向的就是执行上下文对象,this是在函数调用时才发生的绑定,它指向什么完全取决于函数在哪里被调用。

二.绑定规则
要想找出this指向的是什么,就要先找到函数执行的调用位置。调用位置是函数在执行过程中被调用的位置而不是声明的位置。比如:
function a(){ console.log('a'); }
function b(){
console.log('b')
a();--->调用位置
}
a();--->调用位置

1.默认绑定

默认绑定也叫全局绑定。
在非严格模式下,当执行函数时,如果是不带任何修饰的函数引用进行调用的,就是默认绑定。
当使用默认绑定时,this指向的是全局对象。
举个例子:
var a = 1;
function aa(){
console.log(this.a);
}
function bb(){
var a = 2;
console.log(this.a);
aa();
}
bb();//输出 1,1

2.隐式绑定(作为对象的属性调用)

当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
举个例子:
function aa(){
console.log(this.a);
}
var obj = {
a:2,
aa:aa
};
obj.aa(); // 2

因为调用 aa()时,this绑定到obj,所以this.a 与 obj.a是一样的。
需要注意的是,对象属性引用链中,只有上一层或者最后一层在调用位置中起作用。

隐式丢失:
隐式绑定的函数在某些情况下可能会丢失绑定对象,从而使用默认绑定(非严格模式)。
举个例子:
function aa(fn){
console.log(this.a);
}
function doAA(fn){
fn(); <---调用位置
}
var obj = {
a:2,
aa:aa
}
var a = "global";
doAA(obj.aa); // "global"

参数传递其实就是一种隐式赋值,fn是obj.aa的一个引用,但是它引用的是函数本身。所以fn()前面没有带任何的修饰函数调用,因此用了默认绑定。

回调函数丢失this绑定这种情况是格外需要注意的。

3.通过call,apply 显式绑定
如果我们不想在对象内部包含函数引用,而是想在某个对象上强制调用函数,那么就可以使用call或者apply来调用。绝大多数函数都可以使用这2个方法。
这两个方法第一个参数是一个对象,是将要绑定到this的对象 ,第二个参数是要向执行函数传递的参数。举个例子:
function aa{
console.log(this.a);
}
var obj = {
a:2
}
aa.call(obj);

通过aa.call(),把this绑定在obj上。

4.new绑定
在javascript中,构造函数只是一些使用new操作符时被调用的函数。它们不属于某个类,它们只是被new操作符调用的普通函数而已。使用new来调用函数时,这个新对象就会绑定到函数调用的this。举个例子:
function aa(a){
this.a = a;
}
var bb = new aa(2);
console.log(bb.a);//2

使用new来调用aa()时,就会构造一个新对象绑定到aa()调用中的this上。

三.优先级

现在我们已经知道了有这些绑定规则,但是如果某个调用位置对应多个规则怎么办,所以要给这些规则制定优先级。
以下优先级由高到低:
1.new绑定。
2.call,apply调用绑定。
3.由上下文调用绑定,即隐式绑定。
4.默认绑定:在严格模式下绑定到undefined,否则绑定到全局对象。

四.例外的箭头函数

箭头函数不是使用function来定义的,而是使用箭头定义的,它不使用this的四条规则,它会继承外层函数调用的this绑定,非常需要注意的一点是箭头函数的绑定时无法修改的!举个例子:
function aa(){
return (a) => {
console.log(this.a);
}
}
var obj_1 = {
a:1
}
var obj_2 = {
a:2
}
var ss = aa.call(obj_1) // 1
ss.call(obj_2) // 1
上面aa()函数的this绑定到obj_1,所以箭头函数也绑定到obj_1,后面再修改this指向obj_2,,但是不行的,还是输出1。

PS:有错误欢迎指出,转载请注明出处。

以上参考:
《你不知道的javascript》this的讲解

怎样优雅地编写公共组件

公共组件的设计模式根据需求大致可以分成两种模式,构造函数模式和模块模式。一般来说,如果需要一个对象的多个不同实例,就使用构造函数模式,否则使用模块模式。

举个栗子:

构造函数模式:
let Fruits = function(){
let config = { //配置项
name:'apple',
cb:null //回调函数
}
function addName(){

}
function getName(){
return name;
}
function init(opt){
Object.assign(config,opt); //对象浅复制
}
init(opt);
//暴露给外界的方法
return {
getName:getName
};};

调用:
let obj1 = new Fruits({
name:'banana',
cb:function(){
alert('');
}
});

模块模式:
let Dialog = (function(){
let config = {
title:'温馨提示',
message:'',
btn:{
sure:{},
cancel:{}
}
}
function alert(){
}
function confirm(){
}
//对外暴露的方法
return {
alert,
confirm
}
}())
调用:
Dialog.alert('参数出错');

两种模式都要遵循的规则:

一.命名空间

命名空间有助于减少程序中所需要的全局变量数量,并且同时还有助于避免命名冲突或

过长的名字前缀。js语言没有内置命名空间,但是我们可以去实现它。可以为应用程序创建一个全局对象,然后将所有功能添加到这个全局对象中,从而在具有大量函数,对象和其他变量的情况下不会污染全局范围。

最佳实践就是创建一个闭包:

let obj = function(){ 其他功能函数写在这里... }
二.声明依赖关系

在模块顶部声明代码所以来的模块是一个非常好的实践。举个例子:

let myFunction = function(){ let event = M.util.Event, dom = M.util.Dom; //使用事件和Dom变量 }
顶部声明依赖关系有许多优点:

1.显示声明依赖向用户表明了他们确定需要的特定脚本文件已经包含在这个页面中。

2.顶部的前期声明开发者很容易发现,并且去解析依赖。

3.解析局部变量的速度要比解析全局变量要快,提升性能。

三.配置参数

每个组件都需要一定的传参,包括函数需要的外界参数,回调函数等,这些参数如果用一个配置项统一管理起来,可以提高可读性性和可维护性。举个例子:

let myFunction = (function(){
let config = {
color:'#fff', //可以先给一个默认值
width:'100px',
height:'100px',
cb:function(){ //默认回调函数
}
}
function init(opt){
Object.assign(config,opt);//这一步是必须的,用于把外部的参数浅复制到内部的配置项,
也就是说如果已经存在某个特定参数,后面传的参数会覆盖它,
如果没有传该参数,那就使用默认值
}
return {
init:init
}
}())
四.私有和特权成员

前面已经说过,要给组件创建一个单独的命名空间,也就是闭包,在闭包范围内的变量和函数都不应该随意的暴露给外界,因为外界的用户可能会随意更改我们的对象。

为了区分私有成员和公共成员,可以return出一个对象,是暴露给外界的接口。在命名上面,私有成员可以加一个前缀 “_”下划线,用以区分。举个例子:

let myFunction = (function(){
let config = {
color:'#fff', //可以先给一个默认值
width:'100px',
height:'100px',
cb:function(){ //默认回调函数
}
}
function _fuc1(){ //私有方法
}
function fuc2(){ //公共方法
}
function init(opt){
Object.assign(config,opt);
}
return {
init:init,
fuc2:fuc2
}
}())
注意:

私有性失效:

有一个特别需要注意的问题是,当直接从一个私有方法返回一个私有变量,并且该变量恰好是一个对象或者数组,那么外面的代码仍然可以访问到这个私有变量,因为它是通过引用传递的。解决的方法很简单,返回的变量可以是对象的一个拷贝,即一个副本。用Object.assign()就可以解决啦。

PS:如有错误欢迎指正!

以上参考:

1.工作时的总结

2.书籍:《javascript模式》

字符串与正则表达式的优化

一. 字符串连接:

实现字符串连接的方法有很多,有“+=”,array.join(),string.concat()。当连接少量字符串时,所有函数都很快,但是当合并字符串的长度和数量增加后,差别就很大了。
1.+和+=:这是连接字符串最简单的方法。不同的浏览器,合并字符串是分配内存的方法不同。除IE外,浏览器都是通过扩展左端基本字符串的内存,然后把后面的字符串都拷贝到它的尾部,所以提高优化的方法是尽可能减少拷贝字符串的长度和避免临时字符串。IE7和更早浏览器在连接字符串时使用更糟糕的实现方法。所以如果要兼容早期浏览器的话,最好就不要使用这种方法。
2.array.join():这是一种补偿方法。在大多数浏览器上它比连接字符串慢。但是在IE7及更早版本浏览器上,它是连接大量字符串的高效方法。
3.string.concat():这是连接字符串最灵活的方法。它可以接受任意数目参数。它比+和+=更慢一些。
4.在字符组内部,点号是元字符,但是在内部则不是。

二.正则表达式优化:

粗浅地编写正则表达式是造成性能瓶颈的主要原因。还有很多可以改进正则表达式效率的地方。每种浏览器的正则表达式引擎也有不同的内部优化。

1.理解正则表达式的解析过程:编译-设置起始位置-匹配每个正则表达式的字元-匹配成功或失败。
2.匹配关键点:回溯:回溯是整体性能的唯一因素。理解它的工作原理,以及如何减少使用频率,可能是编写高效正则表达式最重要的关键点。
比如贪婪量词的匹配,匹配了开始字元成功后,遇到贪婪字符,它会先吞噬剩下的全部字符串,再回溯匹配,如果匹配失败次数太多,匹配的速度会变慢。
3.提高正则表达式的更多方法:关注如何让匹配更快失败。

(1)减小分支数量,缩小它们的范围。
分支使用 | ,竖线,可能要求在字符串的每一个位置上测试所有的分支选项。可通过使用字符
类和选项组件减少对分支的需求。例如用/[cb]at/代替/cat|bat /
(2)使用非捕获组:捕获组花费时间和内存用于记录后向引用,并保持它们是最新的。如果你不需要一个后向引用,可通过
使用非捕获组避免这种开销——例如,(?:…)替代(…)。
(3)捕获感兴趣的文字,减少后处理。
(4)暴露所需字元。
例如,正则表达式/^(ab|cd)/暴露它的字符串起始锚。
(5)使用适当的量词。贪婪量词可能会引起次数较多的回溯。
(6)将复杂的正则表达式拆分为简单的片断
尽量避免一个正则表达式做太多的工作。复杂的搜索问题需要条件逻辑,拆分为两个或多个正则表达式
更容易解决,通常也更高效,每个正则表达式只在最后的匹配结果中执行查找。

4.小心使用正则表达式。
小心使用它,是非常快的。
当搜索那些不依赖正则表达式复杂特性的文本字符串时,可以不用正则表达式,这样有助于避免正则表达式带来的性能开销。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.