简介
JS(JavaScript)是一门编程语言,负责页面的行为交互。
用途:客户端、特效、动画、交互、数据校验。。。。
服务器端 node
语法
书写位置
-
嵌入式:可以放在文本任何位置,建议放在body末尾。
<script> alert("hello world!") </script>
-
外链式:(实际项目中)推荐使用
<script src="./my.js"></script>
-
行内式(了解)
<p onclick="alert('ok');"></p>
js常见语句
// 弹窗
alert("...")
// 换行
\n
// 在页面中输出content信息
document.write("content");
// 在控制台的Console打印content信息
console.log("content")
变量
含义:
未知数,存储一个值,这个值可以发生改变。
定义:var 变量名;
var x;
var a, b;
赋值
x = 10; // 把10赋值给x。
var x = 10;
变量类型
// 变量名 $ _ 数字 字母 不能以数字开头 不能是关键字
var i = 10; //
// 基本类型
// number 数字 整数、小数、负数
// string 字符串 "hello"、'world'
// boolean 布尔值 true/false
// undefined 未赋值的变量类型就是undefined
// null
// 引用类型
数组、函数、对象、正则、日期。。。
运算符
算术运算符
// + - * /
"3" + "4" --> "34" 字符串拼接
// 只要有字符串参与,就是字符串拼接
10 + "5" --> "105"
自增、自减运算符
var x = 10;
x++; // x=11 自增运算符
x--; // x=10 自减运算符
var k;
k = x++; // k=10; x=11;
k = ++x; // k=11; x=11;
关系运算符
a > b a比b大为true
a < b a比b小为true
字符串比较大小时,从第一个开始比较,第一个相等再比较第二个,以此类推
a >= b a大于等于b为true
a <= b a小于等于b为true
a == b a内容等于b内容为true
a === b a内容和类型等于b内容和类型为true
"12a">=5 false
"12a"<=5 false
"12a"==5 false
当有数字与字母组合参与比较时,结果总是为false "12a"结果为NaN
逻辑运算符
&& 与,表达式左边与右边要同时满足才为true
|| 或,表达式左边与右边只要满足一个即为true
短路问题
&&左边表达式为false,则右边不执行
||左边为true,则右边不执行
条件表达式
表达式?值1:值2
当表达式成立时,结果采用值1,否则,结果采用值2
0表示false,采用值2
用户输入问题
parseInt() 把括号里的内容转化成数字
// 监听用户输入
prompt()
类型转换
parseInt() 把第一个非数字字符之前的数字转化成整数,不包含小数,若首位是字符,则NaN
parseFloat() 把第一个非数字且非小数点字符之前的数字转成整数
Number() 只要有字母,就不能转化,只要含有非小数点其他字符结果就是NaN
Number() true--> 1 false--> 0
Boolean() 非空字符串为true,空字符串为false;非0数字为true,0为false
进制转换
// 转成二进制数
num.toString(2)
// 转成八进制数
num.toString(8)
扩展方法
isNaN() 判断是否NaN类型。
// 执行
eval()
流程控制
顺序结构
从上到下,从左到右
分支结构(选择结构)
if
var age = 20;
if (age >= 18) {
// 条件成立执行此内容
alert("恭喜,您可以考取驾照!");
}
if…else…
var age = 20;
if (age >= 18) {
// 条件成立执行此内容
alert("恭喜,您可以考取驾照!");
} else {
// 条件不执行此内容
alert("对不起,您尚未达到规定年龄");
}
多分支
var score = parseInt(prompt("请输入你的分数:"));
if(score >= 90) {
console.log("A");
} else if(score > 80) {
console.log("B");
} else if(score >= 60) {
console.log("C");
} else {
console.log("D");
}
if嵌套
var grade = prompt("请输入您的级别: ");
var age = parseInt(prompt("请输入您的工龄: "));
if(grade === "初级") {
if(age === 1) {
console.log("10000");
} else if(age === 2) {
console.log("15000");
} else {
console.log("18000");
}
} else if(grade === "中级") {
if (age >= 4 && age <= 5) {
console.log("25000");
}
} else if(grade === "高级") {
if (age >= 5) {
console.log("30000")
}
}
switch
var day = parseInt(prompt("请输入一个整数0——6"));
switch(day) {
case 0: console.log("星期日");break;
case 1: console.log("星期一");break;
case 2: console.log("星期二");break;
case 3: console.log("星期三");break;
case 4: console.log("星期四");break;
case 5: console.log("星期五");break;
case 6: console.log("星期六");break;
default: console.log("输入错误!");
break;
}
循环结构(重复结构)
while()
while(条件表达式) {
循环体;
}
// 打印1000句我爱你中国
var i = 0;
while(i < 1000) {
console.log("我爱你中国!");
i++;
}
do…while()
do {
循环体;
} while(条件表达式)
var i = 0;
do {
console.log("我爱你中国!");
i++;
} while(i < 10)
for()
for(表达式1; 表达式2; 表达式3) {
循环体;
}
for(var i = 0; i < 10; i++) {
console.log("我爱你中国!");
}
死循环
while(true) {
循环体;
}
for(; ;) {
循环体;
}
break&continue
break用于循环表示结束循环
continue用于表示本次循环结束,继续下一次循环。
函数
概念
希望某些逻辑或者特定功能的代码块可以被我们控制或者反复使用,此时可以考虑用函数封装。
最大好处 提高代码复用
函数定义
// 无参函数
function 函数名() {
// 函数体; --具体代码实现
}
// 示例 有参函数名
// 函数定义时指定的参数叫形式参数 简称形参,形参之剑以,隔开
function() getSum(a, b) {
return a + b;
}
// 函数调用的时候传入的参数叫实际参数 简称实参
getSum(10, 20);
函数表达式
var 函数名 = function() {
// 函数体
}
函数调用
函数名();
arguments
函数内置一个对象arguments,接收我们所有的实参
arguments.length -- // 表示实参个数
arguments.callee -- // 表示arguments所在的函数
函数名.length -- // 函数形参个数
根据arguments.length 和 函数名.length 可以控制判断实参是否符合形参个数
return关键字
用于返回值
function getSum(a, b) {
return a + b;
}
递归函数
函数自己调用自己
// 求n的阶乘
function fnFac(n) {
if (n === 1) {
return 1;
} else {
return n * fnFac(n - 1);
}
}
对象
数据类型
基本数据类型
Boolean
Number
String
Undefined
Null
Symbol
引用数据类型
Object
对象是一个整体 从语法角度就是一个无序属性的集合
对象由特征和行为组成,特征在程序中通过属性描述
行为用函数描述
// :之前是属性,:之后是值
var along = {
name: "along",
age: 33,
xueli: 'benke',
birthday: {
year: 1988,
month: 9,
day: 10
},
teacher: function() {
console.log("带大家月薪破30k");
}
}
along['age'] -- 访问along对象中的age属性
var age = 'age';
along[age]; -- 等同于along['age']
动态添加属性
along.wx = "zxl7621485";
数组
基本数据类型和引用数据类型的区别
- 基本数据类型不能动态添加属性
- 引用数据类型能动态添加属性
Math()
Math()常用方法
Math.abs(num);、 // 求num绝对值
Math.ceil(num, num2);// 向上取整
Math.floor(num, num2);// 向下取整
Math.max(); // 求最大值
Math.min(); // 求最小值
Math.random(); // 产生一个取值范围为[0, 1)的随机数
Math.pow(num, n); // 求num的n次方
Math.round(); // 四舍五入
Date()
创建
var d = new Date();
d --> 返回当前系统日期
分别获取年月日
function dateToString(d) {
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var y = d.getFullYear();
var m = toTwo(d.getMonth() + 1);
var _d = toTwo(d.getDate());
var h = toTwo(d.getHours());
var _m = toTwo(d.getMinutes());
var s = toTwo(d.getSeconds());
var weekday = d.getDay();
var str = y + '年' + m + '月' + _d + '日';
str += h + ':' + _m + ':' + s + ' ';
str += arr[weekday];
return str;
}
// 若v值不满足两位数则在前面加0
function toTwo(v) {
return v < 10 ? '0' + v : v;
}
toLocaleString()
获取本地当前日期
Date.parse(str)
返回一个时间戳
Window对象
window对象表示浏览器窗口对象。
setInterval(function(){}, timer)
定时器,重复执行 详情请查看前端demo
setInterval(function(), 延时时间(ms));
var i = 10;
var timer = setInterval(function() {
console.log(i--);
if (i === 0) {
clearInterval(timer); // 取消定时器
}
}, 1000)
setTimeout(function(){}, timer)
延时器,只执行一次
var timer = setInterval(function() {
alert('弹窗'); // 只一次弹窗
}, 1000)
ES6(ECMAScript)
ES6(ECMAScript)欧洲计算机制造商协会制定的一个标准
let&const
let特点:
-
不允许重复定义
-
不存在变量声明提升
-
支持块级作用域
// 定义变量var 允许重复定义,变量声明提升,不能定义常量,不支持块级作用域
let a = 10;
let a = 10; // 报错
console.log(b); // 报错, 没有变量声明提升
let b = 20;
const:定义常量,定义时需要初始化数据
const PI = 3.141592653
PI = 3.14 // 报错
解构赋值
let arr = [1, 2, 3];
let [a, b, c] = arr;
console.log(a, b, c); // 结果打印为 1,2,3;
let {name, age} = {
name: 'along',
age: 32
}
console.log(name);
console.log(age);
// 重命名
let {name: name1, age: age1} = {
name: 'along',
age: 32
}
console.log(name1);
console.log(age1);
// 获取数组里对象, 要注意一一对应
let [, {hobby}] = [{
name: 'along',
age: 32
}, {
hobby: ['coding', 'running']
}]
console.log(hobby);
// 默认解构 c默认30,若对象里有值,则以对象里的值为准
let {a, c = 30} = {a: 10, b: 20}
字符串
模版字符串
- 反单引号``
- 遇到变量用
${变量名}
- 原理:正则
// 模版字符串
let name = 'along';
let age = 32;
let res = `My name is ${name}, I am ${age} years old`;
console.log(res);
模版标签
function tag(str) {
// 打印['My name is ', ', I am ', 'years old']
console.log(str);
let res = '';
let arr = [];
let arr2 = arguments[0];
for(let k in arguments) {
if (k != 0) {
arr.push(arguments[k]);
}
}
for(let key in arr) {
res += arr2[key].toUpperCase() + arr[key].toString();
}
res += arr2[arr2.length -1].toUpperCase();
console.log(res)
}
let res = tag`My name is ${name}, I am ${age} years old`;
startsWith(str)
功能:以str开头
返回值:true or false
let url = 'http://www.baidu.com';
// 以http开头的返回true 反之返回false,区分大小写
let flag = url.startsWith('http');
endWith(str)
功能:以str结尾
返回值:true or false
let img_name = '2.png';
let bool = img_name.endWith('png');
includes(str)
功能:是否包含str
返回值:true or false
console.log('along666'.includes('666')); // true
repeat(num)
功能:让字符串重复num次
'abc'.repeat(3);
padStart(length, fillNum)/padEnd(length, fillNum)
功能:补位
'0'.padStart(8, 7); // 表示总共8位,在0前面补7位7
'0'.padEnd(8, 7); // 表示总共8位,在0后面补7位7
展开运算符
let arr1 = [10, 20, 30];
let arr2 = [2, 4, 6];
let newArr = [...arr1, ...arr2];
console.log(newArr); // [10, 20, 30, 2, 4, 6];
let uname = {
name: 'zs'
};
let age = {
age: 30
};
let stu = {...uname, ...age};
console.log(stu); // {name: 'zs', age: 30}
函数
- 默认参数
function fn(a, b) { return a + b; } // 传默认值, 默认为0 function fn(a = 0, b = 0) { return a + b; } fn(5); // 结果为5 fn(); // 结果为0
- 剩余运算符
// num2类型为数组 function fn2(num, ...num2) { } fn2(10); // num2 无值 fn2(10, 20, 30, 40); // num1为10,num2为[20, 30, 40]
- 箭头函数
// es6以前函数 function fn(a = 0, b = 0) { return a + b; } // es6函数 let arrow = (a = 0, b = 0) => { return a + b; } // 若函数体只有一条执行语句,可省略花括号和return let arrow = (a = 0, b = 0) => a + b;
数组新api
Array.from()
function fn() {
// let arr = Array.from(arguments);
let arr = [...arguments];
// 以上两种方式等价
}
Array.of()
Array.of(3); // 把3作为值传入一个数组,并且长度为1
fill(start, end)
let arr = [1, 2, 3, 4, 5];
// 从序号第1个开始,第2位结束[start, end)
arr.fill('a', 1, 2);
copyWithin(start, end, tag)
let arr = [1, 2, 3, 4, 5];
// 从第0个开始,第一个结束(不包括),重复1个数排列
arr.copyWithin(0, 1, 2);
排序
冒泡排序(bubbleSort)
n个数比较n-1轮次,每轮进行若干次相邻两束比较
var arr = [10, 2, 3, 12, 0, -1, 22];
/*
i=0 [0]~[1] [1]~[2] ... [5]~[6] 0-5
i=1 [0]~[1] [1]~[2] ... [4]~[5] 0-4
...
i=5 [0]~[1]
得出 规律是 i + 每轮比较的数都是5
*/
// 控制轮数
for(var i = 0; i < arr.length-1; i++) {
// 相邻两个数比较
for(var j = 0; j < arr.length-1-i; j++) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
console.log(arr);
选择排序(selectSort)
// 10 3 -3 11 0
var arr = [10, 3, -3, 11, 0];
var temp = 0;
// 第一轮拿第一个数字与后面的数进行比较
// 第二轮拿第二个数字与后面的数进行比较
for(var i = 0; i < arr.length; i++) {
for(var j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
DOM
DOM简介
DOM(Document Object Model)文档对象模型
dom树:每个标签代表dom树每个节点
DOM事件
三要素:事件类型(具体什么行为)、事件源(谁身上发生该行为)、事件处理
js程序如何处理事件
事件源.事件 = 事件处理函数
var btn = document.getElementById('btn');
btn.onclick = function() {
alert('hello world!');
}
window.onload()
页面加载完事件
onmouseover()
鼠标移入事件(一般与onmouseout搭配使用) 视频参考:大前端day16视频4
onmouseout()
鼠标移出事件(一般与onmouseover搭配使用) 视频参考:大前端day16视频4
onchange()
改变内容时
oninput()
当输入时就执行
onfoucs()
获取焦点事件
onblur()
失去焦点事件
innerHTML()
表示元素内部内容,支持HTML标签
innerText()
表示元素内部内容,不支持HTML标签
查找元素方法
根据id找
document.getElementById(id);
根据标签名查找
查找所有tagName集合无论找几个要加[]
document.getElementsByTagName(tagName);
根据querySelector查找
(查找一个)
document.querySelector(selector);
根据querySelectorAll查找
查找所有满足selector的集合,无论有几个都要加[]
document.querySelectorAll(selector);
根据name属性查找
document.getElementsByName(name);
根据class属性查找(注意兼容问题)
document.getElementsByClassName(className);
操作样式
with
// oDiv.style.width = '300px';
// oDiv.style.height = '300px';
// oDiv.style.backgroundColor = 'pink';
with(oDiv.style) = {
width: '300px',
height: '300px',
backgroundColor: 'red'
}
给标签设置class属性
.box {
width: 300px,
height: 300px,
border: 3px solid red;
}
// 若标签元素原本没有class属性
oDiv.className = 'box';
// 若标签元素原本有class属性
oDiv.className = oDiv.className + 'box';
排他思想
var as = document.getElementsByTagName('a');
var divs = document.getElementsByClassName('content');
for(var i = 0; i < as.length; i++) {
as[i].index = i;
as[i].onclick = function() {
// 排他思想,先全部移除样式,再单独设置自己
for(var j = 0; j < as.length; j++) {
as[j].className = '';
divs[j].style.display = 'none';
}
this.className = 'on';
divs[this.index].style.display = 'block';
}
}
js获取自定属性
<a href='#' index='1'>111</a>
// 可以获取自定义属性
this.getAttrbute('index');
// 无法获取自定义属性
this.index; // undefinder
节点关系
节点(一般指的是元素节点):元素节点、属性节点、文本节点
元素节点 | 属性节点 | 文本节点 | 注释节点 | |
---|---|---|---|---|
nodeType | 1 | 2 | 3 | 8 |
nodeName | 大写标签名 | 大写标签名 | #test | #comment |
nodeValue | null | null | 文本内容 | 注释内容 |
根据parentNode查找父元素
<div>
<p>
<a id='remove'>删除元素</a>
</p>
</div>
<script>
var a = document.querySelector('#remove');
a.parentNode(); // 找到父元素p
console.log(a.nodeName); // 节点名称
console.log(a.nodeType); // 节点类型 1表示元素节点
</script>
firstChild 获取元素第一个子节点,若是没有则显示文本节点
a.firstChild(); // 获取元素第一个子节点
childNodes:包含文本子节点
children:只包含元素节点
末尾动态添加元素
var oDiv = document.creatElement('div');
document.body.appendChild(oDiv);
在任意位置添加元素,第一个参数是要插入的元素,第二个参数是需要参照的元素
var oDiv = document.createElement('div');
document.body.document.insertBefore(oDiv, document.body.children[0]);
动态删除元素
oDiv.onclick = function() {
this.remove();
}
元素克隆
cloneNode()
<div id="box">
<img src="./start.gif" alt="">
</div>
<script>
var box = document.querySelector('#box');
// 浅层克隆 无法复制子元素
// var boxClone = box.cloneNode();
// 深层克隆 可以复制所有子元素
var boxClone = box.cloneNode(true);
</script>
文档碎片
var cache = document.createDocumentFragment();
for(var i = 0; i < 1000; i++) {
var btn = document.createElement('input');
btn.type = 'button';
btn.value = '按钮';
cache.appendChild(btn);
}
document.body.appendChild(cache);
创建元素
document.write();
innerHTML
document.createElement();
增加元素
appendChild()
insertBefore()
删除元素
removeChild()
remove()
修改属性
自定义属性 元素.属性
src
href
title
非自定义属性
// 设置属性
setAttribute()
// 获取属性
getAttribute()
修改元素内容
// 支持HTML标签
innerHTML
// 仅设置文本。
innerText
修改表单元素
value
type
disable
checked
修改元素样式
style.***
className
找元素
关系属性
parentNode()
children()
previousElementSibling()
nextElementSibling()
DOM事件
删除事件/解绑事件
DOM0 事件源.事件 = null;
DOM事件流
页面接受事件的顺序,事件发生后会在元素节点之间按照某种顺序传播
doucment->html->body->div->body->html->document
捕获阶段 当前目标阶段 冒泡阶段
使用addEventListener事件
事件源.addEventListener(‘事件名’, function(){}, 是否捕获)
有的事件不具有冒泡
焦点事件、onmouseenter/onmouseleave
事件对象
box.onclick = function(e) {
// 做兼容
var e = e || event
// 这样就能获取到事件对象
console.log(e);
}
常见属性
target 触发事件的元素
this 绑定事件的对象
preventDefault() 阻止浏览器默认行为 比如链接跳转 存在兼容问题
return false 也可以阻止浏览器默认行为且不存在兼容问题
stopPropagation() 阻止冒泡行为
cancelBubble() IE低版本使用这种方式
事件冒泡
给父元素绑定单击事件,点击子元素,父元素绑定的单击事件会执行
<div class="box" id="box">
<div class="son" id="son">
我是儿子
</div>
</div>
<script>
function $(id) {
return document.getElementById(id);
}
$('box').onclick = function () {
console.log(event);
console.log(event.target); // 当前触发事件的这个元素
console.log(this); // 绑定事件的这个元素
}
</script>
事件委托
给父元素绑定事件,只操作一次DOM 提高程序性能
<ul>
<li>11111</li>
<li>22222</li>
<li>33333</li>
<li>44444</li>
<li>55555</li>
</ul>
<script>
var oUl = document.querySelector('ul');
oUl.onclick = function(e) {
var e = e || window.event;
console.log(e.target);
}
</script>
常用鼠标或键盘事件
鼠标事件
-
单击:onclick
-
鼠标移入移出(存在冒泡):onmouserover/onmouseout
-
鼠标移入移除(不存在冒泡):onmouseenter/onmouseleave
-
鼠标按下弹起:onmouseup/onmousedown
键盘事件
- 获取焦点失去焦点:onfocus/onblur
- 键盘弹起按下:keyup/keydown
- 键盘按下(过程)不能识别功能键:keypress
文本上下文:oncontextmenu
// 阻止浏览器右键弹出选项
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
});
// 阻止复制文本
document.addEventListener('selectstart', function(e) {
e.preventDefault();
});
鼠标事件对象
clientX:相对于浏览器窗口可视区域的X轴坐标
clientY:相对于浏览器窗口可视区域的Y轴坐标
screenX:相对于电脑屏幕的X轴坐标
screenY:相对于电脑屏幕的Y轴坐标
pageX(兼容IE9+):相对于文档页面的X轴坐标
pageY(兼容IE9+):相对于文档页面的Y轴坐标
键盘事件对象
keyCode:获取键盘按下的ASCII码值(keyup/keydown中大小写一致,keypress区分大小写)
BOM
-
BOM简介(Browser Object Model)
-
window对象(定时器)
浏览器的顶级对象 :
1 js访问浏览器窗口的一个接口;
2 全局对象 定义在全局作用域中的变量或函数自动变成window对象的属性和方法
-
页面加载事件
window.onlad = function() {}
窗口加载事件 指的是文档内容完全加载(图片、脚本、css等)完成触发事件
DOMContentLoaded DOM加载完毕 不包含样式 图片 flash等
如果文档图片较多并且在onload事件中不会操作图片,可以采用DOMContentLoaded()方法;如果有操作图片,则必须采用onload()方法。
窗口大小事件 window.onresize = function() {}
-
定时器(做动画的基础)
window.setTimeout(函数, 延时时间) 如果不写延时时间或者设置0 实际上系统会改成4ms;
clearTimeout(timeoutId)
window.setInterval(函数, 延时时间)
clearInterval(timeoutId);
-
location对象/navigator对象/history
location.href() 获取或设置当前页面的url
location.host() 获取当前页面的主机名
location.search() 获取参数
// 4s后当前页面跳转到百度页面 setTimeout(function() { location.href = "www.baidu.com"; }, 4000); // location其他方法 /** * 使用location.href 浏览器会记录历史,而使用location.replace则* 不会记录历史 * location.assign() 和href一样 * location.replace() 替换当前页面, 不能后退,浏览器不记录历史 * location.reload() 重新加载页面 */
-
navigator对象
可以获取userAgent信息。可以获取用户访问设备类型。
-
history对象
back(); forword(); go();/** * history 常用有三种方法,分别是back()、forword()、go().。 */
-
offset系列
-
el.offsetParent: 表示元素中带有最近定位的祖先元素,若祖先元素都没有定位,则返回body元素
-
el.offsetTop: 表示元素距离offsetParent的top距离,若祖先元素都没有定位,则返回body元素
-
el.offsetLeft: 表示元素距离offsetParent的左边(left)距离,若祖先元素都没有定位,则返回body元素
-
el.offsetWidth:表示元素的可视宽度,包括border、padding、width。
-
el.offsetHeight:表示元素的可视高度,包括border、padding、width。
特点:以上属性返回值不带单位
offset与style的比较
offset | style |
---|---|
获得的数据没有单位 | 带单位的字符串 |
得到任意样式表达式 | 只获取行内样式 |
offset包含三部分 | style.width只包含width |
offset只读 | style可读写 |
client
可以动态获取元素边框大小、元素大小
- el.clientTop: 上边框的值,没有单位
- el.clientLeft:左边框的值,没有单位
- el.clientWidth:返回元素的宽度,包含width和左右padding的值
- el.clientHeight:返货元素的高度,包含width和上下padding的值
scroll
- el.scrollTop:被卷去上侧距离
- el.scrollLeft:被卷去左侧距离
- el.scrollWidth:返回自身实际宽度,不包含边框
- el.scrollHeight:返回自身实际高度,不包含边框
scroll事件:当滚动条发生变化,哪怕是1像素也会触发
当滚动事件为文档时,获取当前页面滚动的距离可以用 window.pageYOffset
获取
动画
利用定时器,加上offsetLeft或者offsetTop的偏移量
获取计算后的样式
getComputedStyle(obj, false)[style];
存在兼容问题
function getStyle(obj, attr) {
if(window.getComputedStyle) {
return window.getComputedStyle(obj, false)[attr];
} else {
return obj.currentStyle[attr];
}
}