第2章--进阶篇

类型进阶

类型:

Undefined

Null

Boolean

String

Number

Object

原始类型(值类型):undefined, null, true, "...", 123

对象类型(引用类型):var obj = {};  var arr = [];  var date = new Date();

JS的三大对象类型:

原生对象:

JS语言规范(ECMA规范)所定义的一系列对象。

可分为两部分:

构造函数:用开发者定义的内置构造函数来定义一系列对象

由Boolean/ String/ Number/ Object/ Function/ Array/ Date/ RegExp/ Error组成

对象:Math, JSON, 全局对象,arguments

宿主对象:

浏览器运行环境提供的一系列对象,包括window, document, history, navigator等

这些对象提供了诸如dom操作等的API,开发者可操作网络节点等。(在DOM课程详解)

浏览器扩展对象:各浏览器厂商为自己的浏览器所扩展的浏览器对象

早期--为不同浏览器开发不同页面--兼容性

规范的发展--浏览器扩展对象慢慢被弃用--了解即可

原始类型和对象类型的区别:

问:如何复制一个对象?如何克隆出一个独立但属性、方法完全一样的对象

https://www.zhihu.com/question/23031215

隐式类型转换:(弱类型语言)

什么时候发生隐式类型转换呢:

1. 数字运算符

i.e.

10 + <input type="text" id="num"/>
<input type="button" value="等于" id="btn"/>
<span id="ret"></span> <script type="text/javascript">
var btn = document.getElementById("btn");
var ret = document.getElementById("ret");
var num = document.getElementById("num");
btn.addEventListener('click', function() {
ret.innerText = 10 + num.value;
})
</script>

此时会将10隐式转换成String后进行+的字符串连接操作 // 1010

若是ret.innerText = 10 - num.value; // num.value字符串会被隐式转换成数字后进行算术运算

总结:除了+运算外,当一方是数字、另一方为字符串时,会被隐式转换为数字进行计算

当为+运算时,会被隐式转换为字符串进行拼接

2.  .

将直接量隐式转换成对象后即可调用该对象的方法。

i.e.

(3.1415).toFixed(2);  // "3.14"

console.dir(3.1415);  // undefined

系统在进行 . 操作时,进行了隐式类型转换成对象类型(该例为一个Number对象)。

"hello world".split(" ");  // 将"hello world"直接量隐式转换成了String对象。

3. if语句

条件语句的条件会被隐式转换成boolean类型的值

4. ==

隐式类型转换结果:

显式类型转换

以上例为例子:ret.innerText = 10 + Number(num.value);  // 20

Number(), String(), Boolean()

parseInt(), parseFloat()  // 取数值

!, !!  // 取布尔值

类型识别:

什么时候需要使用到类型识别呢?

i.e. function toDate(param) {

// 输入格式: '2015-08-05'/ 1438744815232/ {y:2015, m:8, d:5}/ [2015,8,5]

// 返回格式:Date

function toDate(param) {
if (typeof(param) == 'string' ||
typeof(param) == 'number') {
return new Date(param);
}
if (param instanceof Array) {
var date = new Date(0);
date.setYear(param[0]);
...
return date;
}
if (typeof(param) == 'object') {
var date = new Date(0);
date.setYear(param.y);
...
return date;
}
return -1;
}

类型识别的方法:

typeof(...) / typeof ...

typeof "jerry";  // "string"

typeof 12;  // "number"

typeof true;  // "boolean"

typeof undefined;  // "undefined"

typeof null;  // "object" X

typeof {name:"jerry"};  // "object"

typeof function() {};  // "function"

typeof [];  // "object"

typeof new Date;  // "object"

typeof /\d/;  // "object"

function Person() {}; typeof new Person;  // "object"

总结:typeof可以识别标准类型(Null除外);

但是不能准确识别具体的对象类型(function可以)

instanceof

[] instanceof Array;  // true

/\d/ instanceof RegExp;  // true

1 instanceof Number;  // false

"jerry" instanceof String;  // false

function Point(x,y) { ... }

function Circle(x, y, r) { ... }

var c = new Circle(1,1,2);

c instanceof Circle  // ture

c instanceof Point;  // true

总结:可以判别内置对象类型,但是不能判别原始类型;

可以判别自定义对象类型(包括父类子类)

--> 可以判别所有的对象类型

Object.prototype.toString.call

Object.prototype.toString.call(123);  // "[object Number]"

Object.prototype.toString.call("123");  // "[object String]"

Object.prototype.toString.call(function() {});  // "[object Function]"

function Point(x,y){ ... }; Object.prototype.toString.call(new Point(1,2));  // "[object Object]"

总结:可以识别标准类型,可以识别内置对象类型

但是不能识别自定义对象类型

constructor

constructor为构造对象的构造函数本身

当创建一个对象后,会发现对象有一个属性称为constructor

"jerry".constructor === String;  // true (.运算符会隐式转换成对象类型)

(1).constructor === Number;  // true

({}).constructor === Object;  // true

new Date().constructor === Date;  // true

[].constructor === Array;

function Person(name) {...}

new Person("jerry").constructor === Person;  // true

总结:可以判别标准类型(Undefined/Null除外,因为这两个类型没有构造函数)

可以判别内置对象类型

可以判别自定义对象类型

--> 利用constructor自己写类型判断函数:

function getConstructorName(obj) {
return (obj===undefined||obj===null)?obj:(obj.constructor&&obj.constructor.toString().match(/function\s*([^(]*)/)[1]);
}

getConstructorName(undefined); // undefined
getConstructorName(null); // null
getConstructorName(new Date()); // "Date"

函数进阶

函数定义的方法:

1. 函数声明:function name() {}

2. 函数表达式:var name = function() {};

3. 函数实例化(少用不推荐):var name = new Function("..", "..", "return ..");

三种函数定义方法的区别:

定义与调用的顺序:

用声明方式定义的函数,可以在函数被声明之前就调用。

因为JS执行过程:JS虽然是脚本语言,但执行顺序不是简单的逐行执行:

1. 预解析:变量声明、函数定义;2. 单步执行JS代码

函数表达式和函数实例化方式定义的函数,不能在定义前被调用。

重复定义:

函数声明:最后声明的为有效声明。

函数表达式和函数实例化:按定义和调用顺序执行。

若:同一个函数被函数声明和其他方法均定义:

其他方法的定义会覆盖函数声明方式的定义。

总结:

函数声明的特点:函数定义会被前置(预解析);重复定义时以最后一次定义为有效定义。

函数实例化的特点:(由于作用域的关系)除了函数内部作用域外,不会逐级向上而是直接到全局作用域。

--该函数只能访问本地作用域和全局作用域。

var person = {name:"aaa", age:50};
(function() {
var person = {name:"aaa", age:30};
var func = new Function("console.log(person.age);");
func();
}) ();

此时返回的为age=50; 而不是30.

var func = new Function("var person = {name:"aaa", age:10}; console.log(person.age););})();

则会返回age=10,因为是函数内作用域

函数调用的方法:

1. 函数调用模式:func_name(param);

2. 方法调用模式:

var var_name = {

...,

func_name: function(param) { ... }

}

var_name.func_name(args);

3. 构造函数调用模式:new Function("");

4. apply调用模式:

JS中的函数为对象,任何函数中均有apply()方法。

Function.prototype.apply的使用:

function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.move = function(x, y) {
this.x += x;
this.y += y;
}
var p = new Point(0, 0);
p.move(2, 2); // 方法调用模式
var circle = {x:1, y:1, r:1}; // 直接定义一个对象
// 如何实现将circle对象进行move()操作呢
p.move.apply(circle, [2, 1]); // 将p的move的方法借用给circle使用

函数调用模式的区别-this:

在函数调用的时候,会自动添加this和arguments这两个临时变量

this的指向区别:

函数调用模式:this指向全局对象Window(内部嵌套的函数中的this也指向Window)

方法调用模式:this指向该对象(调用者)

构造函数调用模式:this指向被构造的对象

apply (call)调用模式:将this的指向从原对象变为函数中的第一个参数对象(上例中为circle对象)

Arguments:

是类似数组的对象(Array-like)

arguments[index]

arguments.length

函数传参:

原始类型变量按值传递 - call by value

对象类型变量按引用传递 - call by reference???

看起来是的,但是:实际上是按共享传递 - call by sharing

传递时,获取了对象地址的副本,因此指向的是同一个对象,而当在函数内把该变量指向的地址改变了,也并不影响原来的对象。

var count = {a:1, b:1};
var addOne = function(obj) {
obj = {a:2, b:2};
return obj;
}
var ret = addOne(count);
console.log(ret); // Object {a:2, b:2}
console.log(count); // Object {a:1, b:1}

闭包:Closure

函数内部定义的子函数,用到了父函数的变量形成的这一个特定作用域

i.e.

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

debugger时,在Scope中:

Local: this: Window

Closure: a: 1

有哪些功能:

1. 保存函数的执行状态

/*
将字符串中的一些特定字符按顺序用数组中的元素替换,如
var arr = ['c', 'f', 'h', 'o'];
var str = ‘ab4de8g4ijklmn7';
替换后为 'abcdefghijklmno'
*/
// 思路:让函数记住自身被调用的次数
var func = (function(){
var count = 0;
return function(){
return arr[count++];
}
})();
str = str.replace(/\d/g, func);

2. 封装

不让对象使用者直接access/modify某些属性 -- 类似于private

var Car = function(type) {
var status = "stop",
return {
type: type,
start: function() {
status = "driving";
},
stop: function() {
status = "stop";
},
getStatus: function() {
console.log(status);
}
}
}
var audi = new Car("audi");

此时在外部访问audi,则不能直接访问status的值。

3. 性能优化

(减少函数定义时间和内存消耗)

// 不使用闭包
function sum(i, j) {
var add = function(i, j) {
return i+j;
}
}
var startTime = new Date();
for(var i = 0; i < 1000000; i++) {
sum(1,1);
}
var endTime = new Date();
console.log(endTime - startTime); // 195 milliseconds

每次调用sum()时都需要在函数内部定义一个add函数

// 使用闭包
var sum = (function() {
var add = function(i, j) {
return i+j;
}
return function(i,j) {
add(i,j);
}
})()
var startTime = new Date();
for(var i = 0; i < 1000000; i++) {
sum(1,1);
}
var endTime = new Date();
console.log(endTime - startTime); // 17 milliseconds

add()为sum的闭包作用域里的函数,不需要每次都定义,节约了时间

-- 可以将不需要保存状态的频繁调用的函数放入闭包作用域内以优化性能(基于js执行性能考虑,被频繁调用的函数内部定义和调用的帮助函数,如果不需要保存状态,应该将这些帮助函数保存到闭包作用域。)

First-class function:函数可被当做普通变量使用(比如可被作为函数的参数或函数的返回值)

功能:

将函数作为参数:比如.forEach(...)/ .replace(...)/ 异步回调函数 等

将函数作为返回值:Function.prototype.bind (与apply类似)

上例中的Point和circle例子:p.move.apply(circle, [2, 1]);

可使用bind:var circlemove = p.move.bind(circle, 2, 1); 返回的是函数的引用

区别:代码执行完circle不会立即移动,需调用circlemove();来完成移动

NB: 可以绑定为var circlemove = p.move.bind(circle, 1); 调用时circlemove(1);

或绑定为var circlemove = p.move.bind(circle); 调用时circlemove(2, 1);

curry:函数克里化:严格意义:将接受多个参数的函数转化为一个接受单一参数并返回一个接受余下参数并返回结果的新函数的函数的技术

var sum = function(a, b, c) {
return a+b+c;
} --> var sum_curry = function(a) {
return function(b, c) {
return a+b+c;
}
}

更泛化的定义:给函数分步传递参数, 每次函数接受部分参数后应用这些参数,并返回一个函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数的函数,直至返回最后结果。归纳为逐步传参,逐步缩小函数的适用范围,逐步求解的过程。

// currying实现将一个函数转变为柯里化函数
var currying = function (fn) {
var _args = [];
return function () {
if (arguments.length === 0) {
// 实现最终的计算
return fn.apply(this, _args);
}
// 这里只是简单的将参数缓存起来(用于解释柯里化概念,并非实际应用场景)
Array.prototype.push.apply(_args, [].slice.call(arguments));
return arguments.callee;
}
};
// sum函数接受任意参数,并返回求和结果
var sum=function () {
var total = 0;
for (var i = 0, c; c = arguments[i++];) {
total += c;
}
return total;
};
// 或得一个泛化柯里化的sum函数
var sum_curry = currying(sum);
sum_curry(1)(2,3);
sum_curry(4);
console.log(sum_curry());

从更上层的角度去理解,柯里化允许和鼓励你将一个复杂过程分割成一个个更小的更容易分析的过程(这些小的逻辑单元将更容易被理解和测试),最后这样一个难于理解复杂的过程将变成一个个小的逻辑简单的过程的组合。

上面两个例子很好的解释了什么是函数柯里化,但是什么时候用?任何能简化逻辑实现、提高可读性地方都鼓励使用

i.e.

// refresh函数实现通过ajax请求更新页面上的相关模块的数据。
function refresh(url, callback){
// ajax_get实现一个ajax get请求,请求成功后回调callback函数(这里不提供ajax_get实现,有兴趣的同学可以参考前面课程中有提到过类似的实现)。
ajax_get(url, callback);
} function update(data){
// 更新的逻辑全部在这里处理
}
refresh("xxx?target=news", update); // update函数是一个柯里化后函数,第一级函数根据传入参数将需要更新的模块分拆出来。
function update(target){
var _elm = document.getElementById(target); // 这里实现模块分拆,代码仅是举例
return function(data){ // 返回一个用请求结果更新页面显示的函数
_elm.innerHTML = data; // 这里实现用ajax请求返回结果更新页面显示过程,代码仅是举例
}
}
// 更新页面可以写成这样
refresh("xxx?target=news", update("news"));
refresh("xxx?target=pictures", update("pictures")); // 继续,如果新闻模块需要继续拆分成“社会”新闻,“娱乐”新闻,那我们柯里化的update函数该怎么写呢?可以这样写:
function update(target){
var _elm = document.getElementById(target); // 这里实现第一级模块分拆,代码仅是举例
return function(type){ // 返回一个接受其余参数的函数
var _elm = document.getElementById(item); // 这里实现第二级模块分拆,代码仅是举例
return function(data){ // 返回一个接受其余参数并最终更新页面显示的函数
_elm.data = data; // 这里实现用ajax请求返回结果更新页面显示过程,代码仅是举例
}
}
}
// 更新页面就可以写成这样
refresh("action.do?target=news&type=society", update("news")("society"));
refresh("action.do?target=news&type=entertainment", update("news")("entertainment"));

思考题1:函数声明和函数表达式定义同一个函数时,执行的是哪个?

// 以下代码执行时,三次打印分别输出什么?为什么?

function add1(i){
console.log("函数声明:"+(i+1));
}
add1(1); var add1 = function(i){
console.log("函数表达式:"+(i+10));
}
add1(1); function add1(i) {
console.log("函数声明:"+(i+100));
}
add1(1);

101,11,11

思考题2:对象方法中定义的子函数,子函数执行时this指向哪里?

  1. 以下代码中打印的this是个什么对象?

  2. 这段代码能否实现使myNumber.value加1的功能?

  3. 在不放弃helper函数的前提下,有哪些修改方法可以实现正确的功能?

var myNumber = {
value: 1,
add: function(i){
var helper = function(i){
console.log(this);
this.value += i;
}
helper(i);
}
}
myNumber.add(1);

1. this为helper对象。2. 不能。

3.

//使用闭包
var myNumber={
value:1,
add:function(i){
var that=this,
helper=function(i){
console.log(that);
that.value+=i;
}
helper(i);
}
}
myNumber.add(1);
//使用apply或call
var myNumber={
value:1,
add:function(i){
var helper=function(i){
console.log(this);
this.value+=i;
},
helper.apply(myNumber,[i]);
}
}
myNumber.add(1);
//使用方法调用
var myNumber={
value:1,
helper:function(i){
console.log(this);
this.value+=i;
},
add:function(i){
this.helper(i);
} }
myNumber.add(1);

函数回顾:

函数定义3种方法--区别

函数调用4种模式--本地作用域,this, arguments

闭包和闭包的三个主要功能(保存函数状态、封装、性能优化)

First-class function(函数可作为参数或返回值)

函数的克里化实现 (通过first-class function)

原型

原型是什么:

类是具体事物的抽象--类构造对象:抽象->具体

原型是具体的,用一个现成的对象为原型,去构造新的对象:具体->具体

设置对象的原型:

1. Object.create(proto [, propertiesObject])

传入一个原型对象proto(propertiesObject为新对象的属性定义),返回一个新对象

i.e.

// 定义原型对象
var landRover = {
name: 'landRover',
start: function() {
console.log(this.logo + "start");
};
run: function() {
console.log(this.logo + "run");
};
stop: function() {
console.log(this.logo + "stop");
};
}
// 使用原型创建新的对象
var landWind = Object.create(landRover);
landWind.logo = 'landWind'; var landCruiser = Object.create(landRover);
landCruiser.logo = 'landCruiser'; // 启动
landWind.start();

创建新对象时,landWind/landCruiser中的_proto_指针指向landRover对象(_proto_属性指向原型,不能被直接修改)

新对象可以共享原型的属性和方法。

2. 构造函数:使用prototype设置原型

i.e.

// Car构造函数
function Car(logo) {
this.logo = logo || 'unknown name';
}
// 设置Car的prototype属性
Car.prototype = {
start: function() {
console.log(this.logo + "start");
};
run: function() {
console.log(this.logo + "run");
};
stop: function() {
console.log(this.logo + "stop");
};
}
// 使用原型创建新的对象
var landWind = new Car('landWind');
var landCruiser = new Car('landCruiser'); // 启动
landWind.start();

创建新对象时(landWind),设置对象的原型,_proto_为构造函数的prototype属性,

将新对象(landWind)作为this去执行构造函数(Car),Car.apply(landRover, arguments);

原型链:

i.e.

// 在之前Car的构造函数和Car的prototype属性的基础上

// LandRover的构造函数
function Landrover(serialno) {
this.serialNumber = serialno;
}
// 设置LandRover的prototype属性
LandRover.prototype = new Car('landRover'); // 创建LandRover对象
var landRover1 = new LandRover(10000);
var landRover2 = new LandRover(10001); console.log(landRover1.serialNumber);

1. 定义Car和其prototype

2. 定义LandRover并设置其prototype=new Car('landRover'); 当通过new Car()创建对象时,会有原型指针指向Car.prototype

3. 使用构造函数LandRover创建对象landRover1,使用new LandRover()时,会有原型指针指向LandRover.prototype

4. 事实上,Car.prototype (是一个普通的对象)是通过new Object()创建出来的,会有原型指针指向Object.prototype

5. 从landRover1开始landRover1._proto_->new Car('landRover')._proto_->Car.prototype._proto_->Object.prototype._proto_:原型链

另一方面,(构造)函数本身也是对象,则:

landRover/Car中的_proto_都会指向Function.prototype

而Function.prototype可以通过new Object创建,于是同样的,Function.prototype._proto_->Object.prototype

对象的访问、修改、删除都跟原型链有关

访问对象指针时首先会在对象本身查找,若没有,会随着原型链往上查找。

i.e. console.log(landRover1.serialno);  // 在对象landRover1中直接查找到

console.log(landRover1.toString());  // 随着原型链往上一个一个查找,直到Object.prototype中查找到toString()方法

修改和删除只能作用于对象自身的属性(若属性在原型,则会在自身创建该属性并赋值,不会改变原型)

hasOwnProperty():

每一个对象都拥有hasOwnProperty()(来自Object.prototype)

判断传入的属性是不是对象自身的属性

i.e. landRover1.hasOwnProperty('serialno'); // true

landRover1.hasOwnProperty('logo'); // false

作业:

编码实现下面删除数组中重复元素的功能

[2,4,2,3,4].deleteRepeat() 返回:[2,4,3]

变量作用域

静态作用域:

又称为词法作用域

由程序定义的位置决定,和代码执行顺序无关

var x = 10;
function foo() {
alert(x);
}
function bar() {
var x = 20;
foo();
}
bar();

该例中,若是静态作用域(只跟程序定义的位置有关):

1. 全局作用域:x=10; foo=<function>; bar=<function>

2. foo和bar在全局作用域中,bar的作用域:x=20;

3. 即使foo函数内没有变量x,但是foo函数会在外面(即全局作用域)找到x=10;

动态作用域:

在程序运行时刻决定,使用动态栈(压栈、从栈顶取出)

上例中,若是动态作用域:

1. x=10压入栈,紧接着定义foo:<function>压入栈,最后定义bar:<function>压入栈(此时x=10在最底端)

2. 之后执行bar函数,在bar函数内定义了x=20,将x=20压入栈(此时x=20在最顶端)

3. 紧接着调用了foo函数,foo函数中alert(x); 在栈中查找x的值,离栈顶最近的即为x=20

JS变量作用域:

使用静态作用域

没有块级作用域(比如if/while/for等语句的大括号语句块)

一共有两种作用域:全局作用域、函数作用域

ES5中使用词法环境来管理静态作用域

词法环境:描述环境的对象

包含两部分:

1. 环境记录:用来记录环境里面定义的形参、函数声明以及变量等。

2. 对外部词法环境的引用(outer)

var x = 10;
function foo(y) {
var z = 30;
function bar(q) {
return x + y + z + q;
}
return bar;
}
var bar = foo(20);
bar(40);

最外层创建了全局环境(全局环境也有一个outer引用,值为null)

之后的foo函数创建了foo环境(由于foo是在全局环境中定义的,所以foo函数有一个outer引用指向全局环境)

之后的bar函数创建了bar环境,有一个outer引用指向foo环境

环境记录初始化:(即声明提前)

在每一块代码执行前,会初始化改代码的环境

上例中,

先创建全局环境, outer:null,

全局环境的环境记录:

1. 函数声明(没有形参,跳过第一步形参):foo: <function>

2. 变量:x: undefined; bar: undefined

创建好环境记录后,开始执行全局环境中的代码:

x=10;

bar=foo(20);

此时准备执行foo函数

foo函数执行前,创建foo environment。先扫描整个函数中的内容,将形参、函数声明和变量定义在环境记录中。

foo的环境记录:

1. 形参:y: 20;

2. 函数声明:bar: <function> {formalParameter:..., functionBody:..., scope:指向foo环境(用于之后将outer赋值为scope)

(函数声明和函数表达式的区别:函数声明是提前创建的,函数表达式是执行到该语句的时候才创建的)

3. var定义的变量:z: undefind(此时初始化为undefined而不是30)

创建好foo的词法环境后,开始执行foo函数

z=30;

return bar;

bar(40); 此时准备执行bar函数

创建bar的词法环境:outer引用指向foo的词法环境

1. q=40

2. 没有函数定义

3. 没有var变量

开始执行bar函数

return x + y + z + q; // 这些变量都需要在bar的环境记录里面找。

x: bar:outer->foo:outer->global environment: x=10;

y: bar:outer->foo: y=20

z: bar:outer->foo: z=30

q: bar: q=40

特殊的词法环境:

with:

var foo = "abc";
with({
foo: "bar"
}) {
function f() {
alert(foo);
};
(function() {
alert(foo);
})();
f();
}

全局环境:

outer: null;

f:<function>;

foo:"abc"; with()语句

with语句会创建一个临时的词法环境,将传入的对象中的属性定义到with的词法环境记录中。

(函数声明或var变量定义在with块内或with块外是没有差别的)

with environment:

outer:global;

foo:"bar";

之后为function f(){}定义,跳过

匿名函数创建词法环境Anonymous environment:outer:with environment;

alert(foo); --Anonymous:outer->with:foo="bar";

之后准备执行f();

创建f函数的词法环境:

outer:global:不是with环境。f函数是定义在全局环境内的,所以f函数的scope是全局环境。当f函数开始执行时,它的outer即为global

alert(foo): f:outer->global:foo="abc";

// 如果是函数表达式,则会看是在with内执行的,outer:with env;而函数声明是不管这些的,取决于什么时候定义。

try-catch:

try {
var e = 10;
throw new Error();
} catch (e) {
function f() {
alert(e);
}
(function() {
alert(e);
})();
f();
}

闭包

面向对象

JS进阶篇的单元测验:

http://www.jianshu.com/p/984e7dc3afbe

JS进阶篇的单元作业:

http://www.jianshu.com/p/30274a76ac8d

前端开发工程师 - 02.JavaScript程序设计 - 第2章.进阶篇的更多相关文章

  1. 前端开发工程师 - 02.JavaScript程序设计 - 第1章.基础篇

    第1章--基础篇 JS介绍 html 网页的内容:css 网页的样式:javascript 网页的行为 i.e. hello world <!DOCTYPE html> <html& ...

  2. 前端开发工程师 - 02.JavaScript程序设计 - 期末考试

    期末考试客观题 期末考试主观题 https://www.15yan.com/story/aY0HWAQ7oNU/     1(8分) 函数myType用于根据输入参数返回相应的类型信息. 语法如下: ...

  3. 前端开发工程师 - 01.页面制作 - 第3章.HTML

    第3章--HTML HTML简介 Hyper Text Markup Language:超文本标记语言--用于标记网页的内容 history: html(1991)雏形 -> html4.01( ...

  4. 前端开发工程师 - 01.页面制作 - 第1章.Photoshop切图

    第1章--Photoshop切图 工具.面板.视图 什么是切图? 1. 从设计稿(.psd)中切出网络素材,如按钮.图标.logo.背景图等 2. 编写代码,在代码中使用图片,生成静态页面 --给网页 ...

  5. 前端开发工程师 - 01.页面制作 - 第4章.CSS

    第4章.CSS CSS简介 Cascading Style Sheet 层叠样式表:定义页面中的表现样式 history: CSS1(1996)--CSS2(1998)--着手CSS3草案(拆分成很多 ...

  6. Web前端开发工程师养成计划【转载】

    Web前端开发工程师养成计划(入门篇) 最原始的忠告:这个世界上有想法的人很多,但是有想法又能实现它的人太少! 首先要感谢伟大的Web2.0概念.产品概念.用户体验概念.jQuery插件,是它们在中国 ...

  7. Web前端开发工程师基本要求

    一位好的Web前端开发工程师在知识体系上既要有广度,又要有深度,所以很多大公司即使出高薪也很难招聘到理想的前端开发工程师.现在说的重点不在于讲解技术,而是更侧重于对技巧的讲解.技术非黑即白,只有对和错 ...

  8. 从就业面分析web前端开发工程师就业前景(2011.6)

    案例一 公司名称:法国电信北京研发中心 工作地点:北京 联系方式:hao.luan@orange-ftgroup.com 栾先生 岗位名称:web 前端开发工程师 岗位要求: 1. 计算机或相关专业本 ...

  9. 工具武装的前端开发工程师 Mac 软件清单

    Awesome Mac  这个仓库主要是收集非常好用的Mac应用程序.软件以及工具,主要面向开发者和设计师.有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章<工具武装的前端开发工程 ...

随机推荐

  1. MVC 实现下拉框

    MVC动态实现下拉框的方式有很多种,但是方便快捷的却是很少,现在记录一种常用的下拉框实现方式: 1.先看看视图代码是怎么写的 <div class="form-group col-xs ...

  2. 解决SVN UUID客户端和服务器不一致的问题

    下面是从别的文章中COPY过来的两篇文章,可以完美的解决这个问题: 一. 重新定位SVN的时候,遇到uuid不一致的问题. Google得知可以使用以下命令 有到svnadmin命令:(位于 SVN安 ...

  3. golang刷Leetcode系列 --- 实现strStr()

    实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...

  4. 新手Linux命令学习

    一.dd命令:1.可以复制文件,2.可以制作ios镜像,简单理解就是备份 常用的参数  if 设置输入文件的名称 of  设置输出文件的名称 bs  设置每个“”块“”大小 count  要复制“块” ...

  5. mysql 库和表占用空间查询

    1. 查看该数据库实例下所有库大小,得到的结果是以MB为单位 as sum from information_schema.tables; 2.查看该实例下各个库大小 as total_mb, as ...

  6. C语言实现 "谁是凶手?"

    日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个.以下为4个嫌疑犯的供词.A说:不是我.   a=0B说:是C.   c=1 C说:是D.      d=1D说:C在胡说    ...

  7. mysql 长连接断开问题

    从MySQL 5.0.3开始,默认情况下禁止再连接,这是5.0.13中的新选项,提供了一种以显式方式设置再连接行为的方法. mysql应用程序建立的长连接,大约过8小时会断开[没测过,网上都是这么说的 ...

  8. flash读写学习笔记与spi接口及简单测试验证(三)

    FPGA中的视频图像资源,以及想要永久存储的程序都是要存储在flash中,flash是FPGA一个不可缺少的部分,flash的种类有很多,根据winbond公司的128Mbit Qual SPI接口的 ...

  9. Noip 2011 Day 1 & Day 2

    Day 1   >>> T1   >> 水题一道 . 我们只需要 for 一遍 , 由于地毯是从下往上铺的 , 我们只需要记录该位置最上面的地毯的编号 , 每一次在当前地 ...

  10. ACM数论-快速幂

    ACM数论——快速幂 快速幂定义: 顾名思义,快速幂就是快速算底数的n次幂.其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高. 原理: 以下以求a的b次方来介绍: 把b转换成 ...