JS window对象
概述
浏览器里面,window
对象指当前的浏览器窗口。它也是当前页面的顶层对象,即最高一层的对象,所有其他对象都是它的下属。一个变量如果未声明,那么默认就是顶层对象的属性。
window
有自己的实体含义,其实不适合当作最高一层的顶层对象,这是一个语言的设计失误。最早,设计这门语言的时候,原始设想是语言内置的对象越少越好,这样可以提高浏览器的性能。因此,语言设计者 Brendan Eich 就把window
对象当作顶层对象,所有未声明就赋值的变量都自动变成window
对象的属性。这种设计使得编译阶段无法检测出未声明变量,但到了今天已经没有办法纠正了。
window 对象的属性
window.name
window.name
属性是一个字符串,表示当前浏览器窗口的名字。窗口不一定需要名字,这个属性主要配合超链接和表单的target
属性使用。
该属性只能保存字符串,如果写入的值不是字符串,会自动转成字符串。各个浏览器对这个值的储存容量有所不同,但是一般来说,可以高达几MB。只要浏览器窗口不关闭,这个属性是不会消失的。
window.closed,window.opener
window.closed
属性返回一个布尔值,表示窗口是否关闭。
window.opener
属性表示打开当前窗口的父窗口。如果当前窗口没有父窗口(即直接在地址栏输入打开),则返回null
。
如果两个窗口之间不需要通信,建议将子窗口的opener
属性显式设为null
,这样可以减少一些安全隐患。
window.self,window.window
window.self
和window.window
属性都指向窗口本身,是两个属性只读。
window.frames,window.length
window.frames
属性返回一个类似数组的对象,成员为页面内所有框架窗口,包括frame
元素和iframe
元素。window.frames[0]
表示页面中第一个框架窗口。
如果iframe
元素设置了id
或name
属性,那么就可以用属性值,引用这个iframe
窗口。比如<iframe name="myIFrame">
可以用frames['myIFrame']
或者frames.myIFrame
来引用。
frames
属性实际上是window
对象的别名。因此,frames[0]
也可以用window[0]
表示。但是,从语义上看,frames
更清晰,而且考虑到window
还是全局对象,因此推荐表示多窗口时,总是使用frames[0]
的写法。
window.length
属性返回当前网页包含的框架总数。如果当前网页不包含frame
和iframe
元素,那么window.length
就返回0
。
window.frameElement
window.frameElement
属性主要用于当前窗口嵌在另一个网页的情况(嵌入<object>
、<iframe>
或<embed>
元素),返回当前窗口所在的那个元素节点。如果当前窗口是顶层窗口,或者所嵌入的那个网页不是同源的,该属性返回null
。
window.top,window.parent
window.top
属性指向最顶层窗口,主要用于在框架窗口(frame)里面获取顶层窗口。
window.parent
属性指向父窗口。如果当前窗口没有父窗口,window.parent
指向自身。
对于不包含框架的网页,这两个属性等同于window
对象。
全局对象属性
全局对象属性指向一些浏览器原生的全局对象。
-
window.document
:指向document
对象,注意,这个属性有同源限制。只有来自同源的脚本才能读取这个属性。 -
window.location
:指向Location
对象,用于获取当前窗口的 URL 信息。它等同于document.location
属性。 -
window.navigator
:指向Navigator
对象,用于获取环境信息。 -
window.history
:指向History
对象,表示浏览器的浏览历史。 -
window.localStorage
:指向本地储存的 localStorage 数据。 -
window.sessionStorage
:指向本地储存的 sessionStorage 数据。 -
window.console
:指向console
对象,用于操作控制台。 -
window.screen
:指向Screen
对象,表示屏幕信息。
window.isSecureContext
window.isSecureContext
属性返回一个布尔值,表示当前窗口是否处在加密环境。如果是 HTTPS 协议,就是true
,否则就是false
。
window 对象的方法
window.alert(),window.prompt(),window.confirm()
window.alert()
、window.prompt()
、window.confirm()
都是浏览器与用户互动的全局方法。它们会弹出不同的对话框,要求用户做出回应。注意,这三个方法弹出的对话框,都是浏览器统一规定的式样,无法定制。
(1)window.alert()
window.alert()
方法弹出的对话框,只有一个“确定”按钮,往往用来通知用户某些信息。
window.alert('Hello World');
window.alert()
方法的参数只能是字符串,没法使用 CSS 样式,但是可以用\n
指定换行。
alert('hello\nworld');
(2)window.prompt()
window.prompt()
方法弹出的对话框,提示文字的下方,还有一个输入框,要求用户输入信息,并有“确定”和“取消”两个按钮。它往往用来获取用户输入的数据。
var result = prompt('您的年龄?', 25)
上面代码会跳出一个对话框,文字提示为“您的年龄?”,要求用户在对话框中输入自己的年龄(默认显示25)。用户填入的值,会作为返回值存入变量result
。
window.prompt()
的返回值有两种情况,可能是字符串(有可能是空字符串),也有可能是null
。具体分成三种情况。
- 用户输入信息,并点击“确定”,则用户输入的信息就是返回值。
- 用户没有输入信息,直接点击“确定”,则输入框的默认值就是返回值。
- 用户点击了“取消”(或者按了 ESC 按钮),则返回值是
null
。
window.prompt()
方法的第二个参数是可选的,但是最好总是提供第二个参数,作为输入框的默认值。
(3)window.confirm()
window.confirm()
方法弹出的对话框,除了提示信息之外,只有“确定”和“取消”两个按钮,往往用来征询用户是否同意。
var result = confirm('你最近好吗?');
上面代码弹出一个对话框,上面只有一行文字“你最近好吗?”,用户选择点击“确定”或“取消”。
confirm
方法返回一个布尔值,如果用户点击“确定”,返回true
;如果用户点击“取消”,则返回false
。
var okay = confirm('Please confirm this message.');
if (okay) {
// 用户按下“确定”
} else {
// 用户按下“取消”
}
confirm
的一个用途是,用户离开当前页面时,弹出一个对话框,问用户是否真的要离开。
window.onunload = function () {
return window.confirm('你确定要离开当面页面吗?');
}
这三个方法都具有堵塞效应,一旦弹出对话框,整个页面就是暂停执行,等待用户做出反应。
window.open(), window.close(),window.stop()
(1)window.open()
window.open
方法用于新建另一个浏览器窗口,类似于浏览器菜单的新建窗口选项。它会返回新窗口的引用,如果无法新建窗口,则返回null
。
window.open('https://www.baidu.com');
上面代码会让浏览器弹出百度首页。
open
方法一共可以接受三个参数。
window.open(url, windowName, [windowFeatures])
-
url
:字符串,表示新窗口的网址。如果省略,默认网址就是about:blank
。 -
windowName
:字符串,表示新窗口的名字。如果该名字的窗口已经存在,则占用该窗口,不再新建窗口。如果省略,就默认使用_blank
,表示新建一个没有名字的窗口。另外还有几个预设值,_self
表示当前窗口,_top
表示顶层窗口,_parent
表示上一层窗口。 -
windowFeatures
:字符串,内容为逗号分隔的键值对(详见下文),表示新窗口的参数,比如有没有提示栏、工具条等等。如果省略,则默认打开一个完整 UI 的新窗口。如果新建的是一个已经存在的窗口,则该参数不起作用,浏览器沿用以前窗口的参数。
下面是一个例子。
var popup = window.open(
'somepage.html',
'DefinitionsWindows',
'height=200,width=200,location=no,status=yes,resizable=yes,scrollbars=yes'
);
上面代码表示,打开的新窗口高度和宽度都为200像素,没有地址栏,但有状态栏和滚动条,允许用户调整大小。
第三个参数可以设定如下属性。
- left:新窗口距离屏幕最左边的距离(单位像素)。注意,新窗口必须是可见的,不能设置在屏幕以外的位置。
- top:新窗口距离屏幕最顶部的距离(单位像素)。
- height:新窗口内容区域的高度(单位像素),不得小于100。
- width:新窗口内容区域的宽度(单位像素),不得小于100。
- outerHeight:整个浏览器窗口的高度(单位像素),不得小于100。
- outerWidth:整个浏览器窗口的宽度(单位像素),不得小于100。
- menubar:是否显示菜单栏。
- toolbar:是否显示工具栏。
- location:是否显示地址栏。
- personalbar:是否显示用户自己安装的工具栏。
- status:是否显示状态栏。
- dependent:是否依赖父窗口。如果依赖,那么父窗口最小化,该窗口也最小化;父窗口关闭,该窗口也关闭。
- minimizable:是否有最小化按钮,前提是
dialog=yes
。 - noopener:新窗口将与父窗口切断联系,即新窗口的
window.opener
属性返回null
,父窗口的window.open()
方法也返回null
。 - resizable:新窗口是否可以调节大小。
- scrollbars:是否允许新窗口出现滚动条。
- dialog:新窗口标题栏是否出现最大化、最小化、恢复原始大小的控件。
- titlebar:新窗口是否显示标题栏。
- alwaysRaised:是否显示在所有窗口的顶部。
- alwaysLowered:是否显示在父窗口的底下。
- close:新窗口是否显示关闭按钮。
对于那些可以打开和关闭的属性,设为yes
或1
或不设任何值就表示打开,比如status=yes
、status=1
、status
都会得到同样的结果。如果想设为关闭,不用写no
,而是直接省略这个属性即可。也就是说,如果在第三个参数中设置了一部分属性,其他没有被设置的yes/no
属性都会被设成no
,只有titlebar
和关闭按钮除外(它们的值默认为yes
)。
上面这些属性,属性名与属性值之间用等号连接,属性与属性之间用逗号分隔。
'height=200,width=200,location=no,status=yes,resizable=yes,scrollbars=yes'
另外,open()
方法的第二个参数虽然可以指定已经存在的窗口,但是不等于可以任意控制其他窗口。为了防止被不相干的窗口控制,浏览器只有在两个窗口同源,或者目标窗口被当前网页打开的情况下,才允许open
方法指向该窗口。
window.open
方法返回新窗口的引用。
var windowB = window.open('windowB.html', 'WindowB');
windowB.window.name // "WindowB"
注意,如果新窗口和父窗口不是同源的(即不在同一个域),它们彼此不能获取对方窗口对象的内部属性。
下面是另一个例子。
var w = window.open();
console.log('已经打开新窗口');
w.location = 'http://example.com';
上面代码先打开一个新窗口,然后在该窗口弹出一个对话框,再将网址导向example.com
。
由于open
这个方法很容易被滥用,许多浏览器默认都不允许脚本自动新建窗口。只允许在用户点击链接或按钮时,脚本做出反应,弹出新窗口。因此,有必要检查一下打开新窗口是否成功。
var popup = window.open();
if (popup === null) {
// 新建窗口失败
}
(2)window.close()
window.close
方法用于关闭当前窗口,一般只用来关闭window.open
方法新建的窗口。
该方法只对顶层窗口有效,iframe
框架之中的窗口使用该方法无效。
(3)window.stop()
window.stop()
方法完全等同于单击浏览器的停止按钮,会停止加载图像、视频等正在或等待加载的对象。
window.print()
window.print
方法会跳出打印对话框,与用户点击菜单里面的“打印”命令效果相同。
常见的打印按钮代码如下。
document.getElementById('printLink').onclick = function () {
window.print();
}
事件
window
对象可以接收以下事件。
load 事件和 onl oad 属性
load
事件发生在文档在浏览器窗口加载完毕时。window.onload
属性可以指定这个事件的回调函数。
window.onload = function() {
var elements = document.getElementsByClassName('example');
for (var i = 0; i < elements.length; i++) {
var elt = elements[i];
// ...
}
};
上面代码在网页加载完毕后,获取指定元素并进行处理。
error 事件和 one rror 属性
浏览器脚本发生错误时,会触发window
对象的error
事件。我们可以通过window.onerror
属性对该事件指定回调函数。
window.onerror = function (message, filename, lineno, colno, error) {
console.log("出错了!--> %s", error.stack);
};
由于历史原因,window
的error
事件的回调函数不接受错误对象作为参数,而是一共可以接受五个参数,它们的含义依次如下。
- 出错信息
- 出错脚本的网址
- 行号
- 列号
- 错误对象
老式浏览器只支持前三个参数。
并不是所有的错误,都会触发 JavaScript 的error
事件(即让 JavaScript 报错)。一般来说,只有 JavaScript 脚本的错误,才会触发这个事件,而像资源文件不存在之类的错误,都不会触发。
下面是一个例子,如果整个页面未捕获错误超过3个,就显示警告。
window.onerror = function(msg, url, line) {
if (onerror.num++ > one rror.max) {
alert('ERROR: ' + msg + '\n' + url + ':' + line);
return true;
}
}
onerror.max = 3;
onerror.num = 0;
需要注意的是,如果脚本网址与网页网址不在同一个域(比如使用了 CDN),浏览器根本不会提供详细的出错信息,只会提示出错,错误类型是“Script error.”,行号为0,其他信息都没有。这是浏览器防止向外部脚本泄漏信息。一个解决方法是在脚本所在的服务器,设置Access-Control-Allow-Origin
的 HTTP 头信息。
Access-Control-Allow-Origin: *
然后,在网页的<script>
标签中设置crossorigin
属性。
<script crossorigin="anonymous" src="//example.com/file.js"></script>
上面代码的crossorigin="anonymous"
表示,读取文件不需要身份信息,即不需要 cookie 和 HTTP 认证信息。如果设为crossorigin="use-credentials"
,就表示浏览器会上传 cookie 和 HTTP 认证信息,同时还需要服务器端打开 HTTP 头信息Access-Control-Allow-Credentials
。
URLSearchParams 对象
概述
URLSearchParams
对象是浏览器的原生对象,用来构造、解析和处理 URL 的查询字符串(即 URL 问号后面的部分)。
它本身也是一个构造函数,可以生成实例。参数可以为查询字符串,起首的问号?
有没有都行,也可以是对应查询字符串的数组或对象。
// 方法一:传入字符串
var params = new URLSearchParams('?foo=1&bar=2');
// 等同于
var params = new URLSearchParams(document.location.search);
// 方法二:传入数组
var params = new URLSearchParams([['foo', 1], ['bar', 2]]);
// 方法三:传入对象
var params = new URLSearchParams({'foo' : 1 , 'bar' : 2});
URLSearchParams
会对查询字符串自动编码。
var params = new URLSearchParams({'foo': '你好'});
params.toString()
上面代码中,foo
的值是汉字,URLSearchParams
对其自动进行 URL 编码。
浏览器向服务器发送表单数据时,可以直接使用URLSearchParams
实例作为表单数据。
const params = new URLSearchParams({foo: 1, bar: 2});
fetch('https://example.com/api', {
method: 'POST',
body: params
}).then(...)
上面代码中,fetch
命令向服务器发送命令时,可以直接使用URLSearchParams
实例。
URLSearchParams
可以与URL()
接口结合使用。
var url = new URL(window.location);
var foo = url.searchParams.get('foo') || 'somedefault';
上面代码中,URL 实例的searchParams
属性就是一个URLSearchParams
实例,所以可以使用URLSearchParams
接口的get
方法。
URLSearchParams
实例有遍历器接口,可以用for...of
循环遍历。
var params = new URLSearchParams({'foo': 1 , 'bar': 2});
for (var p of params) {
console.log(p[0] + ': ' + p[1]);
}
// foo: 1
// bar: 2
URLSearchParams
没有实例属性,只有实例方法。
URLSearchParams.toString()
toString
方法返回实例的字符串形式。
var url = new URL('https://example.com?foo=1&bar=2');
var params = new URLSearchParams(url.search);
params.toString()
那么需要字符串的场合,会自动调用toString
方法。
var params = new URLSearchParams({version: 2.0});
window.location.href = location.pathname + '?' + params;
上面代码中,location.href
赋值时,可以直接使用params
对象。这时就会自动调用toString
方法。
URLSearchParams.append()
append()
方法用来追加一个查询参数。它接受两个参数,第一个为键名,第二个为键值,没有返回值。
var params = new URLSearchParams({'foo': 1 , 'bar': 2});
params.append('baz', 3);
params.toString()
append()
方法不会识别是否键名已经存在。
var params = new URLSearchParams({'foo': 1 , 'bar': 2});
params.append('foo', 3);
params.toString()
上面代码中,查询字符串里面foo
已经存在了,但是append
依然会追加一个同名键。
URLSearchParams.delete()
delete()
方法用来删除指定的查询参数。它接受键名作为参数。
var params = new URLSearchParams({'foo': 1 , 'bar': 2});
params.delete('bar');
params.toString()
URLSearchParams.has()
has()
方法返回一个布尔值,表示查询字符串是否包含指定的键名。
var params = new URLSearchParams({'foo': 1 , 'bar': 2});
params.has('bar')
params.has('baz')
URLSearchParams.set()
set()
方法用来设置查询字符串的键值。
它接受两个参数,第一个是键名,第二个是键值。如果是已经存在的键,键值会被改写,否则会被追加。
var params = new URLSearchParams('?foo=1');
params.set('foo', 2);
params.toString()
params.set('bar', 3);
params.toString()
上面代码中,foo
是已经存在的键,bar
是还不存在的键。
如果有多个的同名键,set
会移除现存所有的键。
var params = new URLSearchParams('?foo=1&foo=2');
params.set('foo', 3);
params.toString() // "foo=3"
下面是一个替换当前 URL 的例子。
// URL: https://example.com?version=1.0
var params = new URLSearchParams(location.search.slice(1));
params.set('version', '2.0');
window.history.replaceState({}, '', location.pathname + `?` + params);
// URL: https://example.com?version=2.0
URLSearchParams.get(),URLSearchParams.getAll()
get()
方法用来读取查询字符串里面的指定键。它接受键名作为参数。
var params = new URLSearchParams('?foo=1');
params.get('foo')
params.get('bar')
两个地方需要注意。第一,它返回的是字符串,如果原始值是数值,需要转一下类型;第二,如果指定的键名不存在,返回值是null
。
如果有多个的同名键,get
返回位置最前面的那个键值。
var params = new URLSearchParams('?foo=3&foo=2&foo=1');
params.get('foo')
上面代码中,查询字符串有三个foo
键,get
方法返回最前面的键值3
。
getAll()
方法返回一个数组,成员是指定键的所有键值。它接受键名作为参数。
var params = new URLSearchParams('?foo=1&foo=2');
params.getAll('foo')
上面代码中,查询字符串有两个foo
键,getAll
返回的数组就有两个成员。
URLSearchParams.sort()
sort()
方法对查询字符串里面的键进行排序,规则是按照 Unicode 码点从小到大排列。
该方法没有返回值,或者说返回值是undefined
。
var params = new URLSearchParams('c=4&a=2&b=3&a=1');
params.sort();
params.toString()
上面代码中,如果有两个同名的键a
,它们之间不会排序,而是保留原始的顺序。
URLSearchParams.keys(),URLSearchParams.values(),URLSearchParams.entries()
这三个方法都返回一个遍历器对象,供for...of
循环遍历。它们的区别在于,keys
方法返回的是键名的遍历器,values
方法返回的是键值的遍历器,entries
返回的是键值对的遍历器。
var params = new URLSearchParams('a=1&b=2');
for(var p of params.keys()) {
console.log(p);
}
// a
// b
for(var p of params.values()) {
console.log(p);
}
// 1
// 2
for(var p of params.entries()) {
console.log(p);
}
// ["a", "1"]
// ["b", "2"]