js高级技巧_JavaScript高级程序

js高级技巧_JavaScript高级程序下述内容主要讲述了《JavaScript高级程序设计(第3版)》第22章关于“高级技巧”。一、高级函数函数是第一等公民,所有函数都是对象。1.安全的类型检测JavaScript内置的类型检测机制并非完全可靠。varisArray=valueinstanceofArray;以上代码要返回true,value必须是一个数组,而且还必须与Array构造函数在同个全局作用域中。(Array是w

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

下述内容主要讲述了《JavaScript高级程序设计(第3版)》第22章关于“高级技巧”。

一、高级函数

函数是第一等公民,所有函数都是对象。

1. 安全的类型检测

JavaScript内置的类型检测机制并非完全可靠。

var isArray = value instanceof Array;

以上代码要返回true,value必须是一个数组,而且还必须与Array构造函数在同个全局作用域中。(Array是window的属性)如果value是在另外一个iframe中定义的数组,上述代码则返回false。
注意:BOM的核心对象时window,它表示浏览器的一个实例。在浏览器中,window对象有双重角色,它既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的global对象。
解决上述问题:
Object原生的toString()方法,都会返回一个[object NativeConstructorName]格式的字符串。

function isArray(value) { 
   
    return Array.isArray(value) || Object.prototype.toString.call(value) == "[object Array]"; 
}

function isType(type) { 
   
    return function(obj) { 
   
        return Object.prototype.toString.call(obj) == "[object " + type + "]"
    }
}
var isObject = isType("Object")
var isArray = Array.isArray || isType("Array")

注意:Object.prototype.toString()本身可能被修改!

2. 作用域安全的构造函数

function Person(name, age) { 
   
    this.name = name;
    this.age = age;
}

当使用new调用时,构造函数内用到的this对象会指向新创建的对象实例。

var p1 = new Person("lg", 26);
console.log(p1.name, p1.age);       // lg 26

到不使用new调用时,由于this是在运行时绑定的,直接调用Person(),this会映射到全局对象window上,导致错误对象属性的意外增加。

var p2 = Person("camile", 26);
console.log(p2.name, p2.age);       // TypeError: Cannot read prototype 'name'
console.log(window.name, age);      // camile 26

注意:由于window的name属性用于识别链接目标和iframe的,上述覆盖可能会导致严重的问题。

解决上述问题:作用域安全构造函数

function Person(name, age) { 
   
    if(this instanceof Person) {
        this.name = name;
        this.age = age;
    } else {
        return new Person(name, age);
    }
}

var p3 = Person("camile", 26);      // 这里没有使用new操作符
console.log(p3.name, p3.age);       // camile 26

通过上述模式,意味着锁定了可以调用构造函数的环境。如果使用构造函数窃取模式继承且不使用原型链,会破坏整个继承

function Polygon(sides) { 
   
    if(this instanceof Polygon) {
        this.sides = sides;
        this.getArea = function() { 
   
            return 0;
        }
    }else {
        return new Polygon(sides);
    }
}

function Rectangle(width, height) { 
   
    Polygon.call(this, 4);
    this.width = width;
    this.height = height;
    this.getArea = function() { 
   
        return this.width * this.height;
    }
}

var rect = new Rectangle(2, 4);
console.log(rect.getArea());    // 8
console.log(rect.sides);    // undefined 

Polygon.call(this, 4)用于Polygon构造函数是作用域安全的,this并非Polygon的实例,所以会创建并返回一个新的Polygon对象,并没有实际作用,this得不到增长,所以Rectangle实例中不会有sides属性。

解决上述问题:使用原型模式或者寄生模式
方式一:原型模式

Rectangle.prototype = new Polygon();
var rect = new Rectangle(2, 4);
console.log(rect.getArea());    // 8
console.log(rect.sides);    // 4

方式二:寄生模式

function Rectangle(width, height) { 
   
    var r = new Polygon(4); 
    r.width = width;
    r.height = height;
    r.getArea = function() { 
   
        return r.width * r.height;
    }
    return r;
}

var rect = new Rectangle(2, 4);
console.log(rect.getArea());    // 8
console.log(rect.sides);    // 4

注意
构造函数内部创建的var r = new Polygon(4)与外部创建没有什么不同。不能依赖instanceof来确定对象类型。

rect instanceof Rectangle;  // false
rect instanceof Polygon;    // true

由于存在上述问题,建议在可以使用其他模式的情况下,不要使用这种模式。

3. 惰性载入函数

可以将任和代码分支推迟到第一次调用函数的时候。
因浏览器之间行为差异,多数JavaScript代码包含大量的if语句。
例如,创建兼容性的XMLHttpRequest对象【Ajax与Comet

/* 兼容IE早期版本 */
function createXHR(){ 
   
    if (typeof XMLHttpRequest != "undefined"){
        return new XMLHttpRequest();
    } else if (typeof ActiveXObject != "undefined"){    // 适用于IE7之前的版本
        if (typeof arguments.callee.activeXString != "string"){
            var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                            "MSXML2.XMLHttp"],
                i, len;

            for (i=0,len=versions.length; i < len; i++){
                try {
                    new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    break;
                } catch (ex){
                    //skip
                }
            }
        }

        return new ActiveXObject(arguments.callee.activeXString);
    } else {  // XHR对象和ActiveX对象都不存在,则抛出错误 
        throw new Error("No XHR object available.");
    }
}

如果浏览器中支持内置XHR对象,每次if判断测试就显得多余了!!!
通过惰性载入的技术可以很好的解决上述问题。
方式一:在函数被调用时再处理函数

function createXHR(){ 
   
    if (typeof XMLHttpRequest != "undefined"){
        createXHR = function(){ 
   
            return new XMLHttpRequest();
        };
    } else if (typeof ActiveXObject != "undefined"){
        createXHR = function(){ 
                       
            if (typeof arguments.callee.activeXString != "string"){
                var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                                "MSXML2.XMLHttp"],
                    i, len;

                for (i=0,len=versions.length; i < len; i++){
                    try {
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                    } catch (ex){
                        //skip
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        };
    } else {
        createXHR = function(){ 
   
            throw new Error("No XHR object available.");
        };
    }
    // 调用上述新函数
    return createXHR();
}

方式二:在声明函数时就指定适当的函数

// 自执行,在createXHR声明时,就为其指定了相关创建方法。
var createXHR = (function(){ 
   
    if (typeof XMLHttpRequest != "undefined"){
        return function(){ 
   
            return new XMLHttpRequest();
        };
    } else if (typeof ActiveXObject != "undefined"){
        return function(){ 
                       
            if (typeof arguments.callee.activeXString != "string"){
                var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                                "MSXML2.XMLHttp"],
                    i, len;

                for (i=0,len=versions.length; i < len; i++){
                    try {
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        break;
                    } catch (ex){
                        //skip
                    }
                }
            }

            return new ActiveXObject(arguments.callee.activeXString);
        };
    } else {
        return function(){ 
   
            throw new Error("No XHR object available.");
        };
    }
})();

补充
1. 惰性单例

var getSingle = function(fn) { 
   
    var result;
    return function() { 
   
        return result || (result = fn.apply(this, arguments));
    };
};
// 测试
function testSingle(){ 
   }
getSingle(testSingle)() === getSingle(testSingle)();    // true

2. 系统中提供的页面刷新【回调函数不支持参数】

var refreshPage = (function () { 
   
    var fun;
    function register(callback) { 
   
        fun = callback;
    }
    return function (callback) { 
   
        callback && typeof callback === 'function' ? register(callback) : fun();
    }
})();

// 改写
var refreshPage = (function() { 
   
    var fn;
    return function(callback) { 
   
        callback && typeof callback === 'function' ? fn = callback : fn(); 
    }
})();

4. 函数绑定

函数绑定要创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。

var handler = {
    message: "Event handled",
    handleClick: function(event) { 
   
        console.log(this.message);
    }
};

document.getElementById("btn").addEventListener("click", handler.handleClick);      // undefined
问题在于没有保存handleClick()的环境,this被绑定到了当前DOM按钮上。

// 闭包修正
document.getElementById("btn").addEventListener("click", function() { 
   
    handler.handleClick(event);
});
// 自定义bind方法
function bind(fn, context) { 
   
    return function() { 
   
        return fn.apply(context, arguments);
    };
}
document.getElementById("btn").addEventListener("click", bind(handler.handleClick, handler));
// ES5新增bind方法 Function.prototype.bind
document.getElementById("btn").addEventListener("click", handler.handleClick.bind(handler));

5. 函数柯里化

用于创建已经设置好了一个或多个参数的函数。
其基本方法和函数绑定是一样的:使用一个闭包返回一个函数。
二者区别在于:当函数被调用时,返回的函数还需设置一些传入的参数。

function curry(fn){ 
   
    // 获取参数,并转化为数组(第一个参数为柯里化的函数)
    var args = Array.prototype.slice.call(arguments, 1);
    return function(){ 
   
        // 获取参数,并转化为数组
        var innerArgs = Array.prototype.slice.call(arguments),
            // 所有参数集(最终,有效参数受限于fn)
            finalArgs = args.concat(innerArgs);
        return fn.apply(null, finalArgs);
    };
}

function add(num1, num2){ 
   
    return num1 + num2;
}

var curriedAdd = curry(add, 5);
console.log(curriedAdd(3));   //8

var curriedAdd2 = curry(add, 5, 12);
console.log(curriedAdd2());   //17

var curriedAdd3 = curry(add, 5, 12);
console.log(curriedAdd3(1));   //17
/* 增强版bind */
function bind(fn, context){ 
   
    var args = Array.prototype.slice.call(arguments, 2);
    return function(){ 
   
        var innerArgs = Array.prototype.slice.call(arguments),
            finalArgs = args.concat(innerArgs);
        return fn.apply(context, finalArgs);
    };
}

注意:和上述“函数绑定”中的“自定义bind方法”区分

function enhanchBind(fn, context){ 
   
    var args = Array.prototype.slice.call(arguments, 2);
    return function(){ 
   
        var innerArgs = Array.prototype.slice.call(arguments),
            finalArgs = args.concat(innerArgs);
        return fn.apply(context, finalArgs);
    };
}
document.getElementById("btn").addEventListener("click", enhanchBind(handler.handleClick, handler, event, "函数柯里化"));

二、防篡改对象

一旦把对象定义为防篡改,就无法撤销了。

preventExtensions –> seal –> freeze
isExtensible –> isSealed –> isFrozen

1. 不可扩展对象

默认情况下,所有对象都是可扩展的。意味着,任何时候都可以向对象中添加属性和方法。

var person = {name: "lg"};
person.age = 26;
Object.preventExtensions(person);
person.address = "sd";
console.log(person); // Object {name: "lg", age: 26} address属性没有成功添加
console.log(Object.isExtensible(person)); // false,不可扩展

2. 密封的对象

密封对象不可扩展,而且已有成员的[[configurable]]特性将被设置为false。意味着,不能删除属性和方法。

var person = {name: "lg"};
Object.seal(person);
person.age = 26;
console.log(person);    // Object {name: "lg"} age属性没有成功添加
console.log(Object.isExtensible(person));   // false,不可扩展
console.log(Object.isSealed(person));   // true,密封的

3. 冻结的对象

冻结对象不可扩展、又是密封的,而且已有成员的[[Writable]]特性将被设置为false。如果定义了[[Set]]函数,访问器属性仍可写。

var person = {
    name: "lg",
    _address: "sd"  // 表示私有
};
Object.defineProperty(person, "address", {   // 访问器属性
    get: function() { 
   
        return this._address;
    },
    set: function(add) { 
   
        this._address = add;
    }
})
Object.freeze(person);
person.age = 26;
console.log(person);    // Object {name: "lg", address: "sd"} age属性没有成功添加
person.name = "ligang";
person.address = "shandong";    // ??????

console.log(Object.isExtensible(person));   // false,不可扩展
console.log(Object.isSealed(person));   // true,密封的
console.log(Object.isFrozen(person));   // true,冻结的

对于JavaScript库的作者而言,冻结对象是很有用的,其很好的防止了意外修改库中核心对象。

4. 总结

这里写图片描述

三、高级定时器

JavaScript运行于单线程的环境中,而定时器仅仅只是计划代码在未来的某个时间执行。执行时机不能保证。
定时器对队列的工作方式是,当特定时间过去后将代码插入。注意,给队列添加代码并不意味着对它立即执行,而是能表示它会尽快执行。设定一个150ms后执行的定时器不代表了150ms代码就立刻执行,它表示代码会在150ms后被加入到队列中。如果,在这个时间点上,队列中没有其他东西,那么这段代码就会被执行,表面看上去好像就在精确指定的时间点上执行了。其他情况下,代码可能明显等待更长时间才执行。

谨记:定时器指定的时间间隔表示何时将定时器的代码添加到队列,而不是何时实际执行代码。

1. 重复的定时器

setInterval(),JavaScript引擎“仅当没有该定时器的任何代码实例时“,才将定时器代码添加到队列。这确保了定时器代码加入到队列中的最小时间间隔为指定间隔。
其会存在两个问题:(1)某些间隔会被跳过;(2)多个定时器的代码执行之间的间隔可能会比预期的小。

假如,某个onclick事件处理程序使用setInterval()设置了一该处理是否个200ms间隔的重复定时器。如果事件处理程序花了300ms多一点的时间完成,同时定时器代码也花了差不多的时间,就会同时出现跳过间隔且连续运行定时器代码的情况。

btn.addEventListener("click", function(){ 
   
    // 300ms时间执行
    setInterval(function(){ 
   
        // 执行需要300ms
    }, 200);
});

JavaScript进程时间线
解释:第一个定时器在205ms处添加到队列中,但是直到过了300ms处才能够执行。当执行这个定时器代码时,在405ms处又给队列添加了另外一个副本。在下一个间隔,即605ms处,第一个定时器代码仍在运行,同时在队列中已经有了一个定时器的实例。结果是,在这个时间点上的定时器代码不会被添加到队列中。结果在5ms处添加的定时器代码结束后,405ms处添加的定时器代码就立即执行。

解决上述问题:链式调用setTimeout()

setTimeout(function(){ 
   
    // 处理中
    setTimeout(arguments.callee, interval)
}, interval);

好处:在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且,可以保证在下一次定时器代码执行之前,至少等待指定的间隔,避免了连续的运行。

2. Yielding Processes

运行在浏览器中的JavaScript都被分配了一个确定数量的资源,当页面中存在一个耗时较大的脚本时,会导致浏览器卡死。
此时需要考虑两个问题:(1)该处理是否必须同步完成?(2)数据是否必须按顺序完成?
如果都是“否”,则需要考虑“数组分块”技术。

/** * @array 要处理的项目的数组 * @process 处理项目的函数 * @context 运行函数的环境 */
function chunk(array, process, context) { 
   
    setTimeout(function(){ 
   
        var item = array.shift();
        process.call(context, item);
        if(array.length > 0) {
            setTimeout(arguments.callee, 100);
        }
    }, 100);
}

var data = [12,123,1234,453,436,23,23,5,4123,45,346,5634,2234,345,342];
function printValue(item){ 
   
    var div = document.getElementById("myDiv");
    div.innerHTML += item + "<br>";        
}

chunk(data, printValue); // 函数在全局中,所以无需传入执行环境
console.log(data);       // []

注意:传递给chunk()的数组在处理数据时,数组中的条目也在改变。如果想保持原数组保持不变,应该将数组进行克隆。

var data2 = [1, 2, 3];
chunk(data2.concat(), printValue);
console.log(data2);     // [1, 2, 3]

3. 节流处理

在浏览器中,处理DOM交互需要更多的内存和CUP时间。连续尝试进行过多的DOM相关操作可能会导致浏览器挂起,甚至崩溃。
函数节流背后的基本思想是指:某些代码不可以在没有间断的情况连续重复执行。
目的:只有在执行函数的请求停止了一段时间之后才执行。

/** * @param method 方法 * @param scope 当前函数执行作用域 */
function throttle(method, scope) { 
   
    clearTimeout(method.tId);
    method.tId= setTimeout(function(){ 
   
        method.call(scope);
    }, 100);
}

function resizeDiv(){ 
   
    var div = document.getElementById("myDiv");
    div.style.height = div.offsetWidth + "px";
}

// 节流在resize事件中最常用
window.onresize = function(){ 
   
    throttle(resizeDiv);
};

注意:上述函数是一个debounce,而不是一个throttle。debounce与throttle区别

四、自定义事件

事件是一种叫做观察者的设计模式,是一种创建松散耦合代码的技术。
对象可以发布事件,用来表示在该对象生命周期中某个有趣的时刻到了。然后其他对象可以观察该对象,等待这些有趣的时刻到来并通过运行代码来响应。
观察者模式由两类对象组成:主体和观察者。主体负责发布事件,同时观察者订阅这些事件来观察该主体。
JavaScript设计模式–观察者模式

/* 管理事件的对象 */
function EventTarget(){
    this.handlers = {};    
}

EventTarget.prototype = {
    constructor: EventTarget,
    /** * 添加事件 * @param type 事件类型 * @param handler 事件处理程序 */
    addHandler: function(type, handler){
        if (typeof this.handlers[type] == "undefined"){
            this.handlers[type] = [];
        }

        this.handlers[type].push(handler);
    },
    /** * 触发事件 * @param event 事件对象 */
    fire: function(event){
        if (!event.target){
            event.target = this;
        }
        if (this.handlers[event.type] instanceof Array){
            var handlers = this.handlers[event.type];
            for (var i=0, len=handlers.length; i < len; i++){
                handlers[i](event);
            }
        }            
    },
    /** * 移除事件 * @param type 事件类型 * @param handler 事件处理程序 */
    removeHandler: function(type, handler){
        if (this.handlers[type] instanceof Array){
            var handlers = this.handlers[type];
            for (var i=0, len=handlers.length; i < len; i++){
                if (handlers[i] === handler){
                    break;
                }
            }
            handlers.splice(i, 1);
        }            
    }
};

实例1:

// 事件处理程序
function handleMessage(event){ 
   
    alert("Message received: " + event.message);
}
var target = new EventTarget();
// 添加监听
target.addHandler("message", handleMessage);
// 触发事件
target.fire({ type: "message", message: "Hello world!"});
// 移除监听
target.removeHandler("message", handleMessage);
// 触发事件(无效)
target.fire({ type: "message", message: "Hello world!"});

这里写图片描述
实例2:

function object(o){ 
   
    function F(){ 
   }
    F.prototype = o;
    return new F();
}
// 继承 
function inheritPrototype(subType, superType){ 
   
    var prototype = object(superType.prototype);   //create object
    prototype.constructor = subType;               //augment object
    subType.prototype = prototype;                 //assign object
}

function Person(name, age){ 
   
    EventTarget.call(this);
    this.name = name;
    this.age = age;
}

inheritPrototype(Person,EventTarget);

Person.prototype.say = function(message){ 
   
    this.fire({type: "message", message: message});
};
// 事件处理程序
function handleMessage(event){ 
   
    alert(event.target.name + " says: " + event.message);
}

var person = new Person("Nicholas", 29);
// 监听事件
person.addHandler("message", handleMessage);
// 发布事件
person.say("Hi there.");

这里写图片描述
五、拖放
点击某个对象,并按住鼠标按钮不放,将鼠标移动到另一个区域,然后释放鼠标按钮将对象“放”在这里。
拖放的基本概念:创建一个绝对定位的元素,使其可以用鼠标移动。

<!DOCTYPE html>
<html>
<head>
    <title>Drag and Drop Example</title>
</head>
<body>
    <div id="status"></div>
    <div id="myDiv1" class="draggable" style="top:100px;left:0px;background:red;width:100px;height:100px;position:absolute"></div>
    <div id="myDiv2" class="draggable" style="background:blue;width:100px;height:100px;position:absolute;top:100px;left:100px"></div>
    <script type="text/javascript"> var DragDrop = function(){ 
     // EventTarget为上述实例中对象 // 继承EventTarget,具有事件功能 var dragdrop = new EventTarget(), dragging = null, diffX = 0, diffY = 0; function handleEvent(event){ 
     //get event and target var target = event.target; //determine the type of event switch(event.type){ case "mousedown": if (target.className.indexOf("draggable") > -1){ dragging = target; // 保存x、y坐标上的差值 diffX = event.clientX - target.offsetLeft; diffY = event.clientY - target.offsetTop; // 发布自定义事件 dragdrop.fire({type:"dragstart", target: dragging, x: event.clientX, y: event.clientY}); } break; case "mousemove": if (dragging !== null){ //assign location dragging.style.left = (event.clientX - diffX) + "px"; dragging.style.top = (event.clientY - diffY) + "px"; // 发布自定义事件 dragdrop.fire({type:"drag", target: dragging, x: event.clientX, y: event.clientY}); } break; case "mouseup": // 发布自定义事件 dragdrop.fire({type:"dragend", target: dragging, x: event.clientX, y: event.clientY}); dragging = null; break; } }; //全局接口 // 可以拖放 dragdrop.enable = function(){ 
     document.addEventListener("mousedown", handleEvent); document.addEventListener("mousemove", handleEvent); document.addEventListener("mouseup", handleEvent); }; // 禁止拖放 dragdrop.disable = function(){ 
     document.removeEventListener("mousedown", handleEvent); document.removeEventListener("mousemove", handleEvent); document.removeEventListener("mouseup", handleEvent); }; return dragdrop; }(); DragDrop.enable(); // 监听(订阅)相关自定义事件  DragDrop.addHandler("dragstart", function(event){ 
     var status = document.getElementById("status"); status.innerHTML = "Started dragging " + event.target.id; }); DragDrop.addHandler("drag", function(event){ 
     var status = document.getElementById("status"); status.innerHTML += "<br>Dragged " + event.target.id + " to (" + event.x + "," + event.y + ")"; }); DragDrop.addHandler("dragend", function(event){ 
     var status = document.getElementById("status"); status.innerHTML += "<br>Dropped " + event.target.id + " at (" + event.x + "," + event.y + ")"; }); </script>
</body>
</html>

这里写图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/171277.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 云服务器和虚拟主机哪个好?两者有什么优缺点?「建议收藏」

    云服务器和虚拟主机哪个好?两者有什么优缺点?「建议收藏」云服务器和虚拟主机哪个好?两者有什么优缺点?想必有好多网站站长和中小型企业都被这个问题所困惑。现在小杜就来讲一讲云服务器和虚拟主机分别的特征和差异,小杜我相信大家看完本文后,就不会再被这样的问题所困惑了。云服务器云服务类似于传统的独立主机一样,它有自身独立的IP和宽带资源的,而且云服务器自身带有防火墙等防御工具。可是它不同于传统的独立主机,它可以按照使用者的需求量来增加或是降低服务器的配置,而且可以按照所需所用租用,而且租用云主机建立网站的成本,比传统独立主机建立要低好多。优点:它有独立的IP,独立

  • ubuntu的ssh连不上_ubuntu网络连接没有显示出来

    ubuntu的ssh连不上_ubuntu网络连接没有显示出来之前发在其他的博客上的,现在移动以下位置之前的链接:http://blog.chinaunix.net/uid-69944074-id-5831708.html(原创文章)使用Ubuntu,经常需要需要SSH远程连接,但是有时候会出现问题,难以捉摸,下面参考别人的,在结合自己的尝试总结下吧。服务器配完ubuntu系统以及LNMP环境以后,想用WINSCP远程登录,就需要开启SSH服务才能支持。SSH服务分为客户端和服务器。顾名思义,我想用putty远程登录Ubuntu服务器,所以需要安装SSH s

  • 数据库锁表与解锁_数据库解锁

    数据库锁表与解锁_数据库解锁关键字:数据库锁表与解锁一、mysql锁定表:LOCKTABLEStbl_name{READ|WRITE},[tbl_name{READ|WRITE},…]解锁表:UNLOCKTABLES例子:LOCKTABLEStable1WRITE,table2READ…更多表枷锁;说明:1、READ锁代表其他用户只能读不能其他操作

  • ModelSim安装破解出现Unable to checkout a license.Make sure you licence file…..错误

    ModelSim安装破解出现Unable to checkout a license.Make sure you licence file…..错误说了你们可能不信,装ModelSim软件,今天整整装了一天才弄好,一直出现下面的错误。下面详细说一下解决这个问题的办法:方法一:不正面解决这个问题在FPGA做仿真的时候,可以不需要单独破解版的ModelSim,直接使用Quartus软件自带的ModelSim-Altrea安装上面两个软件,然后在仿真的时候,路径设置对就可以这个时候,你安装的ModelSim在桌面的图标你可以发现是叫ModelSim-Altrea方法二:正面解决这个问题如果你跟我一样,非要安装独立的版本,当你遇到这个问题的

  • Java Web之过滤器(Filter)「建议收藏」

    Java Web之过滤器(Filter)「建议收藏」过滤器(Filter)过滤器实际上就是对web资源进行拦截,做一些处理后再交给servlet。通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理大概流程图如下应用场景自动登录统一设置编码格式访问权限控制敏感字符过滤等…

  • CAD常用命令、快捷键和命令说明大全 「建议收藏」

    CAD常用命令、快捷键和命令说明大全 「建议收藏」CAD常用命令、快捷键和命令说明大全一:常用功能键F1:获取帮助F2:实现作图窗和文本窗口的切换F3:控制是否实现对象自动捕捉F4:数字化仪控制F5:等轴测平面切换F6:控制

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号