欢迎光临
我们一直在努力

HTML中换行造成空格间距的问题详解

阅读(2620)

我们在根据UI提供的原稿做网站的时候,在UI要求还原度很高的情况下,可能经常会遇到,在两个input标签,或者input与span标签之间,会产生多余3个象素空格的问题。如下图:
空格测试
代码如下:

<style>
*{ margin:0; padding:0;}
input{width: 120px; height: 30px;}
</style>
<input type="text" value="空格">
<input type="text" value="测试">

我们明明没有设置边距,可是中间为什么会有差不多3个象素的距离呢?
原因则是在ff,chrome当中(在IE上会屏蔽掉)会将代码中的换行或空格解析为“空文本节点”,所以也就出现了我们所不期望需要的空格。

那有没有什么方法可以解决呢?

一、简单粗爆不换行
写代码的时候不要换行,input等在一行输写,那么将解决该问题。但是代码就变得不再那么容易好看。

二、设置父级块的字体大小为0
这样也能解决问题,代码也好看,但是当你设置了父级的字体大小为0时,你里面又要其它字体要显示,可能就得加span等标签去包裹它,并且重新设置字体大小。

三:设置margin-left为-3象素
使得该元素基于原来的位置向左偏移三个象素,也就看不出有空隙了。

一道常被人轻视的前端JS面试题

阅读(1914)

前言

分享下我曾经出过的一道面试题,此题是我出的一套前端面试题中的最后一题,用来考核面试者的JavaScript的综合能力,很可惜到目前为止的将近两年中,几乎没有人能够完全答对,并非多难只是因为大多面试者过于轻视他。

题目如下:

function Foo() {
  getName = function () { alert (1); };
  return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}

//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

答案是:

//答案:
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3

此题是我综合之前的开发经验以及遇到的JS各种坑汇集而成。此题涉及的知识点众多,包括变量定义提升、this指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级等等。

此题包含7小问,分别说下。

第一问

先看此题的上半部分做了什么,首先定义了一个叫Foo的函数,之后为Foo创建了一个叫getName的静态属性存储了一个匿名函数,之后为Foo的原型对象新创建了一个叫getName的匿名函数。之后又通过函数变量表达式创建了一个getName的函数,最后再声明一个叫getName函数。

第一问的 Foo.getName 自然是访问Foo函数上存储的静态属性,自然是2,没什么可说的。

第二问

第二问,直接调用getName函数。既然是直接调用那么就是访问当前上文作用域内的叫getName的函数,所以跟1 2 3都没什么关系。此题有无数面试者回答为5。此处有两个坑,一是变量声明提升,二是函数表达式。

变量声明提升

即所有声明变量或声明函数都会被提升到当前函数的顶部。

例如下代码:

console.log('x' in window); //true
var x;
x = 0;

代码执行时js引擎会将声明语句提升至代码最上方,变为:

var x;
console.log('x' in window); //true
x = 0;

函数表达式

var getName 与 function getName 都是声明语句,区别在于 var getName 是函数表达式,而 function getName 是函数声明。关于JS中的各种函数创建方式可以看 大部分人都会做错的经典JS闭包面试题 这篇文章有详细说明。

函数表达式最大的问题,在于js会将此代码拆分为两行代码分别执行。
例如下代码:

console.log(x); //输出:function x(){}
var x=1;
function x(){}

实际执行的代码为,先将 var x=1 拆分为 var x; 和 x=1; 两行,再将 var x; 和 function x(){} 两行提升至最上方变成:

var x;
function x(){}
console.log(x);
x=1;

所以最终函数声明的x覆盖了变量声明的x,log输出为x函数。

同理,原题中代码最终执行时的是:

function Foo() {
  getName = function () { alert (1); };
  return this;
}
var getName; //只提升变量声明
function getName() { alert (5);} //提升函数声明,覆盖var的声明

Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
getName = function () { alert (4);}; //最终的赋值再次覆盖function getName声明

getName(); //最终输出4

第三问

Foo().getName(); 先执行了Foo函数,然后调用Foo函数的返回值对象的getName属性函数。

Foo函数的第一句  getName = function () { alert (1); };  是一句函数赋值语句,注意它没有var声明,所以先向当前Foo函数作用域内寻找getName变量,没有。再向当前函数作用域上层,即外层作用域内寻找是否含有getName变量,找到了,也就是第二问中的alert(4)函数,将此变量的值赋值为 function(){alert(1)}。

此处实际上是将外层作用域内的getName函数修改了。

注意:此处若依然没有找到会一直向上查找到window对象,若window对象中也没有getName属性,就在window对象中创建一个getName变量。

之后Foo函数的返回值是this,而JS的this问题博客园中已经有非常多的文章介绍,这里不再多说。

简单的讲,this的指向是由所在函数的调用方式决定的。而此处的直接调用方式,this指向window对象。

遂Foo函数返回的是window对象,相当于执行 window.getName() ,而window中的getName已经被修改为alert(1),所以最终会输出1。

此处考察了两个知识点,一个是变量作用域问题,一个是this指向问题。

第四问

直接调用getName函数,相当于 window.getName() ,因为这个变量已经被Foo函数执行时修改了,遂结果与第三问相同,为1。

第五问

new Foo.getName(); ,此处考察的是js的运算符优先级问题。

js运算符优先级(从高到低):

优先级 运算类型 关联性 运算符
19 圆括号 n/a ( … )
18 成员访问 从左到右 … . …
需计算的成员访问 从左到右 … [ … ]
new (带参数列表) n/a new … ( … )
17 函数调用 从左到右 … ( … )
new (无参数列表) 从右到左 new …
16 后置递增(运算符在后) n/a … ++
后置递减(运算符在后) n/a … —
15 逻辑非 从右到左 ! …
按位非 从右到左 ~ …
一元加法 从右到左 + …
一元减法 从右到左 – …
前置递增 从右到左 ++ …
前置递减 从右到左 — …
typeof 从右到左 typeof …
void 从右到左 void …
delete 从右到左 delete …
14 乘法 从左到右 … * …
除法 从左到右 … / …
取模 从左到右 … % …
13 加法 从左到右 … + …
减法 从左到右 … – …
12 按位左移 从左到右 … << …
按位右移 从左到右 … >> …
无符号右移 从左到右 … >>> …
11 小于 从左到右 … < …
小于等于 从左到右 … <= …
大于 从左到右 … > …
大于等于 从左到右 … >= …
in 从左到右 … in …
instanceof 从左到右 … instanceof …
10 等号 从左到右 … == …
非等号 从左到右 … != …
全等号 从左到右 … === …
非全等号 从左到右 … !== …
9 按位与 从左到右 … & …
8 按位异或 从左到右 … ^ …
7 按位或 从左到右 … | …
6 逻辑与 从左到右 … && …
5 逻辑或 从左到右 … || …
4 条件运算符 从右到左 … ? … : …
3 赋值 从右到左 … = …
… += …
… -= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …
2 yield 从右到左 yield …
yield* 从右到左 yield* …
1 展开运算符 n/a … … …
0 逗号 从左到右 … , …

通过查上表可以得知点”.”的优先级高于new操作,相当于是:
new (Foo.getName)();
所以实际上将getName函数作为了构造函数来执行,遂弹出2。

第六问

new Foo().getName() ,首先看运算符优先级括号高于new,实际执行为

(new Foo()).getName()

遂先执行Foo函数,而Foo此时作为构造函数却有返回值,所以这里需要说明下js中的构造函数返回值问题。

题中,返回的是this,而this在构造函数中本来就代表当前实例化对象,遂最终Foo函数返回实例化对象。

之后调用实例化对象的getName函数,因为在Foo构造函数中没有为实例化对象添加任何属性,遂到当前对象的原型对象(prototype)中寻找getName,找到了。最终输出3。

第七问

new new Foo().getName(); 同样是运算符优先级问题,实际执行为:

new ((new Foo()).getName)();

先初始化Foo的实例化对象,然后将其原型上的getName函数作为构造函数再次new。最终结果为3

===2016年03月23日更新===

这里引用 @于明昊 ,更详细的解释了第7问:

这里确实是(new Foo()).getName(),但是跟括号优先级高于成员访问没关系,实际上这里成员访问的优先级是最高的,因此先执行了 .getName,但是在进行左侧取值的时候, new Foo() 可以理解为两种运算:new 带参数(即 new Foo())和函数调用(即 先 Foo() 取值之后再 new),而 new 带参数的优先级是高于函数调用的,因此先执行了 new Foo(),或得 Foo 类的实例对象,再进行了成员访问 .getName。

jQuery设计思想之写法——方法函数化

阅读(2351)

原生

window.onload = function(){
  ...
};

JQ改为

$(function(){
  ...
});

原生

innerHTML = 123;

JQ改为

html(123);

原生点击事件

oDIV.onclick = function(){};

JQ改为

$('#div1').click(function(){})

小例子:

邦邦的小站_分享Web前端技术和PHP技术的学习心得!

原生

window.onload = function(){
	var oDiv = document.getElementById('div1');	
	oDiv.onclick = function(){
		alert( this.innerHTML );
	};	
};

JQ改为

$(function(){	
	$('#div1').click(function(){		
		alert( $(this).html() );		
	});	
});

jQuery选择器

阅读(1916)

jQuery选择器允许对HTML元素组或单个元素进行操作。
jQuery选择器基于元素的id、标签名、类、属性等”查找”(或选择)HTML元素。它基于已经存在的CSS选择器,除此之外,它还有一些独有选择器。
jQuery中所有选择器都以美元符号开头:$()

id选择器
jQuery #id选择器通过HTML元素的id属性选取指定的元素。
页面中元素的id应该是唯一的,所以您要在页面中选取唯一的元素需要通过#id选择器。
通过id选取元素语法如:$(“#div1”)

类选择器
jQuery类选择器可以通过指定的class查找元素。
语法如:$(“.box”)

标签选择器
jQuery标签选择器基于标签名选取元素。
选取所有<p>标签语法如: $(“p”)
实例:所有p标签的背景颜色更改为红色

$("p").css("background-color","red");

更多实例

选择器 实例 选取
* $(“*”) 所有元素
#id $(“#lastname”) id=”lastname” 的元素
.class $(“.intro”) 所有 class=”intro” 的元素
element $(“p”) 所有 <p> 元素
.class.class $(“.intro.demo”) 所有 class=”intro” 且 class=”demo” 的元素
:first $(“p:first”) 第一个 <p> 元素
:last $(“p:last”) 最后一个 <p> 元素
:even $(“tr:even”) 所有偶数 <tr> 元素
:odd $(“tr:odd”) 所有奇数 <tr> 元素
:eq(index) $(“ul li:eq(3)”) 列表中的第四个元素(index 从 0 开始)
:gt(no) $(“ul li:gt(3)”) 列出 index 大于 3 的元素
:lt(no) $(“ul li:lt(3)”) 列出 index 小于 3 的元素
:not(selector) $(“input:not(:empty)”) 所有不为空的 input 元素
:header $(“:header”) 所有标题元素 <h1> – <h6>
:animated 所有动画元素
:contains(text) $(“:contains(‘W3School’)”) 包含指定字符串的所有元素
:empty $(“:empty”) 无子(元素)节点的所有元素
:hidden $(“p:hidden”) 所有隐藏的 <p> 元素
:visible $(“table:visible”) 所有可见的表格
s1,s2,s3 $(“th,td,.intro”) 所有带有匹配选择的元素
[attribute] $(“[href]”) 所有带有 href 属性的元素
[attribute=value] $(“[href=’#’]”) 所有 href 属性的值等于 “#” 的元素
[attribute!=value] $(“[href!=’#’]”) 所有 href 属性的值不等于 “#” 的元素
[attribute$=value] $(“[href$=’.jpg’]”) 所有 href 属性的值包含以 “.jpg” 结尾的元素
:input $(“:input”) 所有 <input> 元素
:text $(“:text”) 所有 type=”text” 的 <input> 元素
:password $(“:password”) 所有 type=”password” 的 <input> 元素
:radio $(“:radio”) 所有 type=”radio” 的 <input> 元素
:checkbox $(“:checkbox”) 所有 type=”checkbox” 的 <input> 元素
:submit $(“:submit”) 所有 type=”submit” 的 <input> 元素
:reset $(“:reset”) 所有 type=”reset” 的 <input> 元素
:button $(“:button”) 所有 type=”button” 的 <input> 元素
:image $(“:image”) 所有 type=”image” 的 <input> 元素
:file $(“:file”) 所有 type=”file” 的 <input> 元素
:enabled $(“:enabled”) 所有激活的 input 元素
:disabled $(“:disabled”) 所有禁用的 input 元素
:selected $(“:selected”) 所有被选取的 input 元素
:checked $(“:checked”) 所有被选中的 input 元素

jQuery简介

阅读(2353)

初学jQuery的朋友,基本上都会问同一个问题“什么是jQuery?”等类似的问题,理解这个问题对于后面的学习会起到促进作用。以下是我整理出的大家常问的几个问题:

1、什么是jQuery?
2、什么是类库?
3、jQuery与JavaScript有什么关系?
4、JavaScript与java又有什么关系?
5、JavaScript、jQuery、Ajax、Json等又是什么?区别又是什么?
6、不会JS能不能学jQuery?

我相信,很多人对这些技术有着似懂非懂的感觉,不是很了解,以上问题肯定是初学者都会产生的问题,如果你对它有兴趣或者想去驾驭它。那么请跟我来,向jQuery进军!let’s GO!

Q:什么是jQuery?
A:jQuery是继Prototype之后又一个优秀的JavaScript类库,它由美国人John Resig创建,至今已吸引来自世界各地众多的JavaScript高手加入其团队,其宗旨是:写更少的代码,做更多的事(write less,do more)

Q:什么是类库?
A:这是程序中的一个基本概念。所谓类,可以理解为是一组语句的集合,用来描述一组具有共同属性和功能的对象。字面理解也就是说类库就是类的集合。Java和.net的类库意思类似。但是在jQuery中,只是集合了许多的方法功能集合,使我们可以通过简单的代码就能实现复杂的效果。

Q:jQuery与JavaScript有什么关系?
A:jQuery是使用JavaScript编写的,也就是说JavaScript可以任意调用,其他程序并不能很轻易的调用。就好比JavaScript是鸡,jQuery是鸡蛋,鸡只能生鸡蛋。再说的明白些,jQuery是使用JavaScript编写的,就好比鸡蛋是鸡生的。
如果你还不明白再看看另一个例子:
我们可以把JavaScript比喻成文字,假如使用文字写了两本菜谱 《西餐菜谱大全》 和 《中餐菜谱大全》,前者是prototype(在jQuery之前也是一种类库)后者是jQuery。菜谱里面都集合了很多做菜的方法也可以叫做菜的类库。在程序里面呢就叫做类库,方法库,函数库等。

Q:JavaScript与Java又有什么关系?
A:乍眼一看,它们有关系或者是同一家公司的产品,其实它们俩既不是兄弟姐妹也不是同一家公司所开发的,前者是Netscape网景公司开发,后者是Sun公司开发,2009年04月20日,Oracle(甲骨文)宣布以74亿美元收购Sun。(详细的资料可以到网上搜一下)

Q:JavaScript、jQuery、Ajax、Json等又是什么?区别又是什么?
A:读到这里,我想不用再讲JS和jQuery了吧?如果你还认为需要讲解,那你再读读前面的几个问题,肯定就明白了,直接切入正题。
Ajax:全称为“Asynchronous JavaScript and XML”(异步JavaScript和XML),它是由JavaScript+CSS+DOM+ XMLHttpRequest的四种技术的结合,并且JS是Ajax的核心。jQuery将Ajax的实现变得更加轻松容易。Ajax就是咱们常说的局部刷新。
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写的同时也易于机器解析和生成。它基于JavaScript的一个子集。 Json采用完全独立于语言的文本格式,可以简单的理解为数据存储的一种格式或交换方式。

Q:不会JS能不能学jQuery?
A:我不知道大家所指的不会JS是什么程度,但我认为如果你一点都不懂JS那是很难学懂的,因为jQuery是JS的类库。另外如果你懂得其他语言,也可以很快的理解的。如果什么都不会我可以给大家一个快速掌握JS基础的方法,先去看JS的数据类型、变量的定义、函数方法的定义、函数方法的调用以及循环和判断,只要知道上面这几种非常容易学会。看着内容挺多其实很简单,最慢一天就能搞懂。

JavaScript运算符

阅读(1826)

常用的运算符,我为大家大致分为5类(算数运算符、赋值运算符、比较运算符,逻辑运算符、其他运算符)

 

算术运算符:+ – * /

取模:%  取余数

负数:只需要在变量或数值前面加上一个-(减号)即可

自增&自减:++  —

 

赋值运算符:

var a = 1; 赋值

a = a – 1; 等同于 a -= 1; //减法赋值

a = a * 1; 等同于 a *= 1; //乘法赋值

a = a / 1; 等同于 a /= 1; //除法赋值

a = a % 1; 等同于 a %= 1; //取模赋值

比较运算符:==  !=  ===  !==  >  <  >=  <=

逻辑运算符:&&  ||  !

三元运算符:条件 ? 语句1 : 语句2 ;

其他运算符:typeof (判断数据类型) new (对象有关的运算符)

 

作用域、JS预解析机制

阅读(2921)

作用域:

域:空间、范围、区域,作用:读、写

“JS解析器”

1)“找一些东西”var  function 参数

  a = … 

    所有的变量,在正式运行代码之前,都提前赋了一个值:未定义(undefined)。

  fn1 = function fn1(){ alert(2); }

    所有的函数,在正式运行代码之前,都是整个函数块。

  这个过程叫 JS的预解析。

  遇到重名的:只留一个。

  变量和函数重名了,就只留下函数。

2)逐行解读代码:

  表达式:= + – * / % ++ — ! 参数……

  表达式可以修改预解析的值!

例:

<script>
var a = 1;
function fn1(a){
  alert(a);    // undefined
  a = 2;
}
fn1();
alert(a);    // 1

var b = 1;
function fn2(b){
  alert(b);    // 1
  b = 2;
}
fn2(b);
alert(b);    // 1
</script>

JavaScript传参实例:商品价格计算

阅读(5602)

我们使用函数传参是为了重用代码,应当遵循以下原则:
1、尽量保证 HTML 代码结构一致,可以通过父级选取子元素;
2、把核心主程序实现,用函数包起来;
3、把每组里不同的值找出来,通过传参实现。

例:商品价格计算
HTML布局

<ul id="list">
	<li>
  	<input type="button" value="-" />
    <strong>0</strong>
  	<input type="button" value="+" />
    单价:<em>16.5元</em>
    小计:<span>0元</span>
  </li>
	<li>
  	<input type="button" value="-" />
    <strong>0</strong>
  	<input type="button" value="+" />
    单价:<em>10.5元</em>
    小计:<span>0元</span>
  </li>
	<li>
  	<input type="button" value="-" />
    <strong>1</strong>
  	<input type="button" value="+" />
    单价:<em>8.5元</em>
    小计:<span>0元</span>
  </li>
	<li>
  	<input type="button" value="-" />
    <strong>0</strong>
  	<input type="button" value="+" />
    单价:<em>8元</em>
    小计:<span>0元</span>
  </li>
	<li>
  	<input type="button" value="-" />
    <strong>0</strong>
  	<input type="button" value="+" />
    单价:<em>14.5元</em>
    小计:<span>0元</span>
  </li>
</ul>

<p></p>

js实现价格计算

<script>
window.onload = function () {
	var oUl = document.getElementById('list');
	var aLi = oUl.getElementsByTagName('li');
	var aP = document.getElementsByTagName('p');
	var num=0;	//商品总数
	var money=0;	//总价格
	
	//函数传参
	for ( var i=0; i 0 && num >0 ) {
				n--;				
				num--;
				money -= price;
			}
			fun1();	
		};
		aBtn[1].onclick = function () {
			n++;
			num++;
			money += price;
			fun1();
		};
	};	
	
	function fun2(li){
		var oStrong = li.getElementsByTagName ('strong')[0];
		var oEm = li.getElementsByTagName ('em')[0];
		var n = Number(oStrong.innerHTML);  // 数量'0'
		var price = parseFloat(oEm.innerHTML);  // 单价 12.5		
	};		
	
};
</script>

JavaScript函数传参、参数类型

阅读(3771)

函数传递参数,参数=JS的数据类型:数字、字符串、布尔值、函数、对象、未定义

例1:

fn1(100, 'px');

function fn1(a, b) {
  alert(a + b); // 100px
}

fn2('邦邦的小站');

function fn2(a) {
  alert(a.charAt(3)); // 小
}

例2:通过判断传入参数的类型,而执行不同的操作。

fn1(100);
fn1('邦邦的小站');
fn1(function() { alert(1); });

function fn1(a) {
  if (typeof a === 'number' && a === a) {
    alert(a + 20);
  } else if (typeof a === 'string') {
    alert(a.charAt(2));
  } else if (typeof a === 'function') {
    a();
  }
}

JavaScript函数

阅读(2738)

函数的作用是定义一次但却可以多次调用或执行任意次的代码,换句话说,需要重复执行的东西我们就可以把它写成函数。

函数主要分为这么几种:无参函数,单参函数,多参函数,返回值函数,递归函数,匿名函数和构造函数。

无参函数:

函数的声明必须要用到一个关键字function,格式如下:

function 名称()

{

方法体

}

单参函数:

顾名思义,就是只有一个参数的函数叫做单参函数,如下p1就是一个参数,格式如下:

function 名称(p1)

{

方法体

}

多参函数:

顾名思义,就是参数个数大于等于2个的函数,叫做多参函数,如下p1,p2,p3一共3个参数,参数之间使用逗号隔开,格式如下:

function 名称(p1, p2, p3)

{

方法体

}

返回值函数:

就是带有return关键字的返回值函数,它能够把这个函数中执行的最终结果返回。因为在方法体中定义的任何变量,出了这个方法体, 就无法得到,也就是说在函数中定义的变量等在外界是无法得到或直接使用的。

function 名称(p1, p2, p3)

{

return 结果;

}

递归函数:

如果你没有其他的编程基础,那么这个词对你来说应该比较抽象;

举例说明:咱们之前调用函数怎么调用呢?直接把方法名拿过来直接调用即可,如下所示:

function abc()

{

方法体

}

abc();  //此处调用abc这个方法,就会执行abc方法体中的代码。

而递归函数,格式是这样的,如下所示:

function abc()

{

…..

此处N多行程序代码

…..

abc();  //发现什么了没有?在方法体内调用自己,这种函数就叫做递归函数。

}

匿名函数:

就是没有名字的函数。

function()

{

方法体

}

上面的方式就是匿名方法,那么怎么调用呢?它没有名字!同样也很简单,看下面:

var abc = function()

{

方法体

}

abc(); //此处调用这个匿名方法。

构造函数:

如果现在讲解构造函数,有点早了,因为它牵扯到类和对象的概念,在这里你只需要记住这个名字就行了,不需要了解太多,后面只要一说到“构造函数”,你有这个印象,就OK!